swift3.0 CoreGraphics绘图-实现画板

摘要:
Swift 3.0优化了绘图API,它看起来更迅捷//Path currentPointArray。append//刷新视图self-SetNeedsDisplay()}因为我们的点存储在数组中,当您想清空绘图板时,只需清空数组funccleanAll(){allLineArray.removeAll()currentPointArray.removeIll()allPointWidth.removeAll()self.setNeedsDisplay()}查看重新绘制的主逻辑overridefuncdraw{letcontext=UIGraphicsGetCurrentContext()context?.setLineJoin//绘制上一行ifallLineArray。count>0{//遍历上一行iin0.0{//绘制线条上下文?.move//获取当前线条的所有点以保存为图像。˂tmpArr.count{letendPoint:CGPoint=tmpArr[j]context?.strokePath()}}}}}只需设置屏幕捕获范围//保存图片@IBActionfuncsavePic{height:CGFoat=self.view.bborders.size.heightself.saveBtn.frame.height-10letimageSize:CGSize=CGSizeUIGraphicsBeginImageContextview.layer.render(in:UIGraphicsGetCurrentContext()!UIGraphicsEndImageContext()UIImageWriteToSavedPhotoAlbum}//保存图片回调函数图像(_image:UIImage,di dFinishSavingWithError:NSError?

swift3.0对绘图的API进行了优化,看起来更swift了。

看下UI的构造。设置画笔粗细、清空面板和保存到本地

画板哦.gif

下面直接看画板文件

这里我做的比较复杂,记录触摸到的每个点,再连成路径,其实直接用可变路径CGMutablePath可变路径就可以实现。

成员变量

    public var lineWidth:CGFloat = 1
    fileprivate var allLineArray = [[CGPoint]]()   //所有的线    记录每一条线
    fileprivate var currentPointArray = [CGPoint]() //当前画线的点  画完置空 增加到 线数组中
    fileprivate var allPointWidth = [CGFloat]()    //所有的线宽

设置触摸时间,开始时记录第一个点并重绘(不重绘就没有只画一个点得效果),移动时不断记录并重绘。

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let point:CGPoint = (event?.allTouches?.first?.location(in: self))!
        //路径起点
        currentPointArray.append(point)
        self.setNeedsDisplay()
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        let point:CGPoint = (event?.allTouches?.first?.location(in: self))!
        //路径
        currentPointArray.append(point)
        //刷新视图
        self.setNeedsDisplay()
    }

由于我们的点都是存在数组中,当要清空画板时 只要将数组清空就可以了

    func cleanAll(){
        allLineArray.removeAll()
        currentPointArray.removeAll()
        allPointWidth.removeAll()
        self.setNeedsDisplay()
    }

下面看下 重绘的主逻辑

 override func draw(_ rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        context?.setLineCap(.round)
        context?.setLineJoin(.round)
 
        //绘制之前的线
        if allLineArray.count > 0 {
            //遍历之前的线
            for i in 0..<allLineArray.count {
                let tmpArr = allLineArray[i]
                if tmpArr.count > 0 {
                    //画线
                    context?.beginPath()
                    //取出起始点
                    let sPoint:CGPoint = tmpArr[0]
                    context?.move(to: sPoint)
                    //取出所有当前线的点
                    for j in 0..<tmpArr.count {
                        let endPoint:CGPoint = tmpArr[j]
                        context?.addLine(to: endPoint)
                    }
                    context?.setLineWidth(allPointWidth[i])
                    context?.strokePath()
                }
            }
        }
        
        if currentPointArray.count > 0 {
            //绘制当前线
            context?.beginPath()
            context?.setLineWidth(self.lineWidth)
            context?.move(to: currentPointArray[0])
            print(currentPointArray[0])

            for i in 0..<currentPointArray.count {
                context?.addLine(to: currentPointArray[i])
                print(currentPointArray[i])
            }
            context?.strokePath()  
        }
    }

保存成图片可很简单,只要截屏设置范围就行

    //保存图片
    @IBAction func savePic(_ sender: Any) {
        
        let height:CGFloat = self.view.bounds.size.height - self.saveBtn.frame.height - 10
        let imageSize :CGSize = CGSize( self.view.bounds.size.width, height: height)
        UIGraphicsBeginImageContext(imageSize)
        view.layer.render(in: UIGraphicsGetCurrentContext()!)
        let img:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        UIImageWriteToSavedPhotosAlbum(img, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
    }
    
    //保存图片回调
    func image(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo:UnsafeRawPointer) {
        var resultTitle:String?
        var resultMessage:String?
        if error != nil {
            resultTitle = "错误"
            resultMessage = "保存失败,请检查是否允许使用相册"
        } else {
            resultTitle = "提示"
            resultMessage = "保存成功"
        }
        let alert:UIAlertController = UIAlertController.init(title: resultTitle, message:resultMessage, preferredStyle: .alert)
        alert.addAction(UIAlertAction.init(title: "确定", style: .default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }

不过千万别忘了给app设置相册的权限

在info.plist中添加Privacy - Photo Library Usage Description属性即可,value值为提示信息

相册权限.png

效果:

效果.png

有兴趣的童靴可可以直接用可变路径实现下 逻辑更简单 完了。

Demo地址

https://github.com/gongxiaokai/paintViewDemo

免责声明:文章转载自《swift3.0 CoreGraphics绘图-实现画板》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇bootstrap DataTable 插件的使用Nginx上部署HTTPS + HTTP2下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Android 手动显示和隐藏软键盘

1、方法一(如果输入法在窗口上已经显示,则隐藏,反之则显示) InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);   imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_...

Spring框架针对dao层的jdbcTemplate操作crud之query查询数据操作

查询目标是完成3个功能: (1)查询表,返回某一个值。例如查询表中记录的条数,返回一个int类型数据 (2)查询表,返回结果为某一个对象。 (3)查询表,返回结果为某一个泛型的list集合。 一、查询表中记录的条数,返回一个int类型数据的操作方法 使用jdbcTemplate 原理是把加载驱动Class.forName("com.mysql.jdbc.D...

EditText 默认不弹键盘 焦点

今天编程碰到了一个问题:有一款平板,打开一个有EditText的Activity会默认弹出输入法。为了解决这个问题就深入研究了下android中焦点Focus和弹出输入法的问题。在网上看了些例子都不够全面,在这里全面总结下。 一:EditText为什么会默认弹出输入法? 同样的代码,碰到有EditText控件的界面时有的机子会弹出输入法,有的机子不会弹出。...

基于python的种子搜索网站-开发过程

本讲会对种子搜索网站的开发过程进行详细的讲解。 源码地址:https://github.com/geeeeeeeek/bt 项目开发过程 项目简介 该项目是基于python的web类库django开发的一套web网站,做为本人的毕业设计。本人的研究方向是一项关于搜索的研究项目。在该项目中,笔者开发了一个简单版的搜索网站,实现了对数据库数据的检索和更新。 网...

重新整理 .net core 实践篇—————中间件[十九]

前言 简单介绍一下.net core的中间件。 正文 官方文档已经给出了中间件的概念图: 和其密切相关的是下面这两个东西: IApplicationBuilder 和 RequestDelegate(HttpContext context) IApplicationBuilder : public interface IApplicationBuilde...

实现自己的.NET Core配置Provider之Yaml

YAML是一种更适合人阅读的文件格式,很多大型的项目像Ruby on Rails都选择YAML作为配置文件的格式。如果项目的配置很少,用JSON或YAML没有多大差别。看看rails项目中的配置文件,如果用JSON写试试什么感受吧。 在《实现自己的.NET Core配置Provider之EF》中已经讲过配置的执行流程,这里不再复述,直接动手。 YamlCo...