swift3.0 CoreGraphics绘图-实现画板
swift3.0对绘图的API进行了优化,看起来更swift了。
看下UI的构造。设置画笔粗细、清空面板和保存到本地

下面直接看画板文件
这里我做的比较复杂,记录触摸到的每个点,再连成路径,其实直接用可变路径
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(width: 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值为提示信息

效果:

有兴趣的童靴可可以直接用可变路径实现下 逻辑更简单 完了。
Demo地址
https://github.com/gongxiaokai/paintViewDemo
swift3.0 CoreGraphics绘图-实现画板的更多相关文章
- 你知道吗, CoreGraphics绘图系统和Bezier贝塞尔曲线坐标系的顺时针方向是相反的!
UIBezierPath是对Core Graphics框架的一种上层封装,目的是让绘图需求可以被更方便的使用. 那你有没有发现被UIBezierPath封装后与之前有什么改变? 答:有三个变化. 1. ...
- Swift3.0服务端开发(一) 完整示例概述及Perfect环境搭建与配置(服务端+iOS端)
本篇博客算是一个开头,接下来会持续更新使用Swift3.0开发服务端相关的博客.当然,我们使用目前使用Swift开发服务端较为成熟的框架Perfect来实现.Perfect框架是加拿大一个创业团队开发 ...
- 算法与数据结构(十三) 冒泡排序、插入排序、希尔排序、选择排序(Swift3.0版)
本篇博客中的代码实现依然采用Swift3.0来实现.在前几篇博客连续的介绍了关于查找的相关内容, 大约包括线性数据结构的顺序查找.折半查找.插值查找.Fibonacci查找,还包括数结构的二叉排序树以 ...
- Swift3.0变化分享
Swift 3.0 做出的改变很大,在这篇文章中,我将尽我所能,利用代码样例给大家解释Swift 3.0最重要(要命)的改变,希望大家能够做好升级Swift 3.0 的准备.Swift 3.0的改变不 ...
- swift3.0变化总结
Swift 3.0 做出的改变很大,在这篇文章中,我将尽我所能,利用代码样例给大家解释Swift 3.0最重要(要命)的改变,希望大家能够做好升级Swift 3.0 的准备.Swift 3.0的改变不 ...
- 关于for循环------swift3.0
在程序开发当中,for循环使用的频率无疑是最高的.常用的swift循环是递增式遍历.当然各种循环,swift都能办到.但其大多采用关键字形式实现,大部分开发者更喜欢直接使用C式循环代码.在swift3 ...
- Swift2.3 --> Swift3.0 的变化
Swift3.0语法变化 首先和大家分享一下学习新语法的技巧: 用Xcode8打开自己的Swift2.3的项目,选择Edit->Convert->To Current Swift Synt ...
- Swift3.0都有哪些变化
从写第一篇Swift文章的时候到现在Swift已经从1.2发展到了今天的3.0,这期间由于Swift目前还在发展阶段并不能向下兼容,因此第一篇文章中的部分代码在当前的Xcode环境中已经无法运行.在W ...
- iOS开发 swift3.0中文版
swift3.0中文版: http://pan.baidu.com/s/1nuHqrBb
随机推荐
- 提高java编程质量 - (三)三目运算符的两个操作数类型尽量一致
先看一个例子: package com.test; public class TernaryOperator { public static void main(String[] args) { in ...
- zookeeper 应用场景概述
Zookeeper主要可以干哪些事情:配置管理,名字服务,提供分布式同步以及集群管理. 一 .配置管理 在我们的应用中除了代码外,还有一些就是各种配置.比如数据库连接,远程服务访问地址等.一般我们都是 ...
- 原生js二级联动
今天说的这个是原生js的二级联动,在空白页面里动态添加并作出相对应的效果. 1 //创建两个下拉列表 select标签 是下拉列表 var sel = document.createElement(& ...
- android开发中关于继承activity类中方法的调用
android开发中关于继承activity类中的函数,不能在其他类中调用其方法. MainActivity.java package com.example.testmain; import and ...
- 初学MySQL
MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品. Mysql默认端口号: 3306 超级用户:root prompt 修改提示符. ( ...
- 容器间通信的三种方式 - 每天5分钟玩转 Docker 容器技术(35)
容器之间可通过 IP,Docker DNS Server 或 joined 容器三种方式通信. IP 通信 从上一节的例子可以得出这样一个结论:两个容器要能通信,必须要有属于同一个网络的网卡. 满足这 ...
- javascript字符串属性及常用方法总结
length属性:str.length; 常用方法: 1. str.charAt(n) 查找字符串中的第n个字符,如果不在0~str.length-1之间,则返回一个空字符串 2 .str.ind ...
- ListView 介绍
1. 通过继承Activity实现ListView 1.1 在XML布局文件中实现一个ListView <ListView android:layout_width="wrap_con ...
- Linux系统网卡设置
由于做了虚拟机的克隆,发现克隆机和被克隆机的MAC地址相同了,下面我将要介绍一下linux中网卡的配置步骤,我使用的linux是CentOS release 6.9 (Final) 1.root用户编 ...
- python自动化运维学习第一天--day1
学习python自动化运维第一天自己总结的作业 所使用到知识:json模块,用于数据转化sys.exit 用于中断循环退出程序字符串格式化.format字典.文件打开读写with open(file, ...