码迷,mamicode.com
首页 > 编程语言 > 详细

Swift-贝赛尔曲线实现画图板 && 截图保存到相册中

时间:2016-05-13 03:06:35      阅读:285      评论:0      收藏:0      [点我收藏+]

标签:

本文内容参考自 传送门原文是用 OC 写的,我把它改成了 Swift 的。

我们先来看看效果图:

技术分享技术分享技术分享

第一幅图是我们画了一个 “iOS” 的图像,第二幅图是我们点击保存成功,第三幅图是可以在相册中看到我们刚才画的图。


感觉很不错有木有?接下来我们就来说说是怎么实现的。

我们分两部分来说:上半部分的画图板和下半部分的控制区。


上半部分的画图板是我们自定义的 view,我们设置如下属性:

class MyView: UIView {
    var color = UIColor.redColor() // 线条颜色
    var lineWidth : Float = 1.0 // 线条宽度
    private var allLine: [Dictionary<String, AnyObject>] = [] // 保存已有的线条
    private var cancelLine: [Dictionary<String, AnyObject>] = [] // 保存被撤销的线条
    private var bezier = UIBezierPath() // 贝赛尔曲线
}
其中线条的颜色和宽度在 controller 中要用到,其余的三个不需要所以我们设置成私有的 private。


先说说后退功能,它其实非常简单。

allLine 和 cancelLine 这两个数组就相当于两个栈。后退时,让已有的一条线出栈,进入到撤销线条的栈中。

具体的代码其实只有短短数行:

func backImage() { // 两个数组相当于两个栈。后退时,让已有的一条线出栈,进入到撤销线条的栈中。
    if allLine.isEmpty == false { // 如果数组不为空才执行
        cancelLine.append(allLine.last!) // 入栈
        allLine.removeLast() // 出栈
        setNeedsDisplay() // 重绘界面
    }
}

前进功能正好和后退相反。前进时,让被撤销的一条线出栈,进入到已有线条的栈中。

func forwardImage() { // 前进时正好与后退相反,让被撤销的一条线条出栈,进入到已有线条的栈中。
    if cancelLine.isEmpty == false { // 如果数组不为空才执行
        allLine.append(cancelLine.last!) // 入栈
        cancelLine.removeLast() // 出栈
        setNeedsDisplay() // 重绘界面
    }
}

接下来说说贝赛尔曲线。对于本例,简单来说就是:

1。在每次开始触摸时新建一个贝赛尔曲线并存入数组中,记录下触摸的坐标作为贝赛尔曲线的当前坐标。

2。在滑动时记录每一瞬时的坐标,更新贝赛尔曲线的当前坐标为这个新坐标。

3。重新绘制界面。

4。执行第二步。直到这次触摸结束为止。


开始触摸时的代码如下:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    bezier = UIBezierPath() // 新建贝塞尔曲线
    let point = touches.first!.locationInView(self) // 获取触摸的点
    bezier.moveToPoint(point) // 把刚触摸的点设置为bezier的起点
    var tmpDic = Dictionary<String, AnyObject>()
    tmpDic["color"] = color
    tmpDic["lineWidth"] = lineWidth
    tmpDic["line"] = bezier
    allLine.append(tmpDic) // 把线存入数组中
}

触摸滑动时的代码如下(没错,就三行,哈哈):

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    let point = touches.first!.locationInView(self) // 获取触摸的点
    bezier.addLineToPoint(point) // 把移动的坐标存到贝赛尔曲线中
    setNeedsDisplay() // 重绘界面
}

重绘界面的代码如下(注意:不要直接调用 drawRect: 方法,如果想重绘的话,调用 setNeedsDisplay() 方法):

override func drawRect(rect: CGRect) {
    for i in 0..<allLine.count {
        let tmpDic = allLine[i]
        let tmpColor = tmpDic["color"] as! UIColor
        let tmpWidth = tmpDic["lineWidth"] as! CGFloat
        let tmpPath = tmpDic["line"] as! UIBezierPath
        tmpColor.setStroke()
        tmpPath.lineWidth = tmpWidth
        tmpPath.stroke()
    }
}

以上几乎就是画图板的全部内容,并不多,而且不难理解。

下面我们来说说如何使用它。在 controller 中创建一个 MyView 的实例,MyView 就是上面所说的画图板。

class ViewController: UIViewController {
    private let drawingBoard = MyView() // 自定义view,也就是画图板部分
    private let mySlider = UISlider() // 滑动条,控制线条宽度
    private let mySegment = UISegmentedControl(items: ["红", "黑", "绿"]) // 分段控制器,控制线条颜色
    private let backBtn = UIButton(type: .Custom)
    private let saveBtn = UIButton(type: .Custom)
    private let forwardBtn = UIButton(type: .Custom)
}

这些 UI 控件的属性设置没啥好说的,无非就是设置 frame、text、title、titleColor、backgroundColor 之类的,不赘述。

我们来说说这些控件的响应事件即可,其实也很简单。


滑动条的响应事件:

func onClickSlider(slider: UISlider) {
    drawingBoard.lineWidth = slider.value
}

分段控制器的响应事件:

func onClickSegment(segment: UISegmentedControl) {
    switch segment.selectedSegmentIndex {
    case 0:
        drawingBoard.color = UIColor.redColor()
    case 1:
        drawingBoard.color = UIColor.blackColor()
    case 2:
        drawingBoard.color = UIColor.greenColor()
    default:
        drawingBoard.color = UIColor.redColor()
    }
}

后退和前进按钮的响应事件:

func onClickBack(button: UIButton) {
    drawingBoard.backImage()
}

func onClickForward(button: UIButton) {
    drawingBoard.forwardImage()
}

最后来说保存到相册的功能。

func onClickSave(button: UIButton) {
    UIGraphicsBeginImageContext(drawingBoard.bounds.size) // 开始截取画图板
    view.layer.renderInContext(UIGraphicsGetCurrentContext()!)
    let img : UIImage = UIGraphicsGetImageFromCurrentImageContext() // 截取到的图像
    UIGraphicsEndImageContext() // 结束截取
    UIImageWriteToSavedPhotosAlbum(img, nil, nil, nil) // 把截取到的图像保存到相册中
    // 最后提示用户保存成功即可
    let alert = UIAlertView.init(title: "存储照片成功",
                                 message: "您已将照片存储于图片库中,打开照片程序即可查看。",
                                 delegate: self,
                                 cancelButtonTitle: "OK")
    alert.show()
}

也许有的同学不知道怎么添加响应事件?那我们就拿后退按钮的响应事件举个栗子

backBtn.addTarget(self, action: Selector("onClickBack:"), forControlEvents: .TouchUpInside)


完整源码请见我的 GitHub:https://github.com/963239327/LZNBezierDrawingBoard 别忘了点击右上角的 star 哦~




Swift-贝赛尔曲线实现画图板 && 截图保存到相册中

标签:

原文地址:http://blog.csdn.net/qq_18425655/article/details/51338310

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!