Swift 全功能的绘图板开发
2015-03-30 08:31
316 查看
转载请注明出处:http://blog.csdn.net/zhangao0086/article/details/43836789。
要做一个全功能的绘图板,至少要支持以下这些功能:
支持铅笔绘图(画点)
支持画直线
支持一些简单的图形(矩形、圆形等)
做一个真正的橡皮擦
能设置画笔的粗细
能设置画笔的颜色和填充颜色
能设置背景色或者背景图
…
我们先做一些基础性的工作,比如创建工程。
先创建一个
语言选择
为了最大程度的利用屏幕区域,我们完全隐藏掉状态栏,在
然后进入到
我们给已存在的
然后我们回到
添加一个放工具栏的容器:
同样的不要选择
在该View里添加一个
铅笔
直尺
虚线
矩形
圆形
橡皮擦
给这个SegmentedControl添加约束:
垂直居中,两边各留20,高度固定为28。
完整的UI及结构看起来像这样:
ImageView将会作为实际的绘制区域,顶部的SegmentedControl提供工具的选择。 到目前为止我们还没有写下一行代码,至此要开始编码了。
你可能会注意到Board有一部分被挡住了,这只是暂时的~
我们创建一个
增加两个属性以及初始化方法:
由于我们是依赖于touches方法来完成绘图过程,我们需要记录下每次touch的状态,比如
在我们实现drawingImage方法之前,我们先创建另外一个重要的组件:
顾名思义,
supportedContinuousDrawing,表示是否是连续不断的绘图
drawInContext,基于Context的绘图方法,子类必须实现具体的绘图
只要是实现了
beginPoint,开始点的位置
endPoint,结束点的位置
lastPoint,最后一个点的位置(也可以称作是上一个点的位置)
strokeWidth,画笔的宽度
这么一来,子类也可以很方便的获取到当前的状态,并作一些深度定制的绘图方法。
我们实现了一个画笔的基类之后,就可以重新回到
我们用
我们需要防止
步骤解析:
开启一个新的ImageContext,为保存每次的绘图状态作准备。
初始化context,进行基本设置(画笔宽度、画笔颜色、画笔的圆润度等)。
把之前保存的图片绘制进context中。
设置
从当前的context中,得到Image,如果是
实时显示当前的绘制状态,并记录绘制的最后一个点。
这些工作完成以后,我们就可以开始写第一个工具了:铅笔工具。
铅笔工具应该支持连续不断的绘图(不断的保存到realImage中),这也是我们给
首先创建一个类,名为
如果lastPoint为nil,则基于beginPoint画线,反之则基于lastPoint画线。
这样一来,一个铅笔工具就完成了,怎么样,很简单吧。
到目前为止,我们的
在
在
最后在
编译、运行,铅笔工具可以完美运行~!
接下来我们把其他的绘图工具也实现了。
其他的工具不像铅笔工具,不需要支持连续不断的绘图,所以也就不用覆盖
创建一个
创建一个
这里我们就用到了
创建一个
我们用到了一些计算,因为我们希望矩形的区域不是由beginPoint定死的。
创建一个
同样有一些计算,理由同上。
从本文一开始就说过了,我们要做一个真正的橡皮擦,网上有很多的橡皮擦的实现其实就是把画笔颜色设置为背景色,但是如果背景色可以动态设置,甚至设置为一个渐变的图片时,这种方法就失效了,所以有些绘图app的背景色就是固定为白色的。
其实Apple的Quartz2D框架本身就是支持橡皮擦的,只用一个方法就可以完美实现。
让我们创建一个
注意,与其他的工具不同,橡皮擦是继承自
加入这一句代码,一个真正的橡皮擦便实现了。
现在我们的工程结构应该类似于这样:
我们修改下
编译、运行:
除了橡皮擦擦除的范围太小以外,一切都很完美~!
在继续完成剩下的功能之前,我想先对之前的代码进行些说明。
其实我最开始也是使用drawRect方法来完成绘制,但是感觉限制很多,比如context无法保存,还是要每次重画(虽然可以保存到一个BitMapContext里,但是这样与保存到image里有什么区别呢?);后来用CALayer保存每一条CGPath,但是这样仍然不能避免每次重绘,因为需要考虑到橡皮擦和画笔属性之类的影响,这么一来还不如采用image的方式来保存最新绘图板。
既然定下了以image来保存绘图板,那么drawRect就不方便了,因为不能用
在
实际上这里包含了两个设计模式。
以我们的绘图板为例,输出不同的图形就意味着不同的算法,用户可根据不同的需求来选择某一种算法,即BaseBrush及其子类做具体的封装,这样的好处是每一个子类只关心自己的算法,达到了高聚合的原则,高级模块(Board)不用关心具体实现,最终我们实现了一个好维护、易拓展的程序(妈妈再也不用担心工具栏不够用了^^)。
策略模式的定义:定义一个算法群,把每一个算法分别封装起来,让它们之间可以互相替换,使算法的变化独立于使用它的用户之上。
在传统的策略模式中,每一个算法类都独自完成整个算法过程,而我们将
模板方法的UML图:
图中右边的方框代表模板方法。
模板方法的定义:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
以上就是我设计时的思路,说完了,接下来还要完成的工作有:
提供对画笔颜色、粗细的设置
背景设置
全屏绘图(不能让Board一直显示不全)
先从画笔开始,Let’s go!
不管是画笔还是背景设置,我们都要有一个能提供设置的工具栏。
所以我们往
拖一个
设置
往
在
在
UIToolbar配置好后,UI及视图层级如下:
考虑到多个页面需要选取自定义的颜色,我们先创建一个工具类:
这个工具类很简单,没有采用Auto Layout进行布局,因为
不过虽然该工具类本身没有采用Auto Layout进行布局,但是它还是支持Auto Layout的,当它被添加到某个Auto Layout的视图中的时候,Auto Layout布局系统可以通过
最后它还有一个
我打算在用户点击
具体的,创建一个
放置一个title为“画笔粗细”的
放置一个title为“1”的
放置一个
放置一个title为“20”的
放置一个title为“画笔颜色”的
放置一个
放置一个
在把
只要get到了这一点,毛玻璃效果就算实现了~~
我们在ViewController新增加几个属性:
我们先写一个往toolbar上添加约束的工具方法:
这个工具方法会把传入进来的view添加到toolbar上,同时添加相应的约束。注意高度的约束,我是通过
然后再增加一个
我们在这个方法里实例化了一个
然后修改
在
由于我们采用了Auto Layout进行布局,动画要通过调用
响应点击“完成”按钮的
这么一来画笔设置就做完了,代码应该还是比较好理解,编译、运行后,应该能看到:
完成度已经很高了^^!
整体的框架基本上已经在之前的工作中搭好了,我们快速过掉这一节。
在
创建
创建一个
放置一个title为“从相册中选择背景图”的UIButton,约束为:左、上边距为8,宽度固定为135,高度固定为30。
放置一个RGBColorPicker,约束为:左、右边距为8,与UIButton的垂直间距为20,底部与superview齐平。
把UIButton的
看上去像这样:
同样用两个Block进行回调;
回到
像
修改viewDidLoad方法:
实现
编译、运行,现在你可以用不同的背景色(或背景图)了!
到目前为止,
),现在是时候来解决它了。
解决思路是这样的:当用户开始绘图的时候,我们把顶部和底部两个View隐藏;当用户结束绘图的时候,再让两个View显示。
为了获取用户的绘图状态,我们需要在
这样一来用户绘图的状态就在ViewController掌握中了。
ViewController想要控制两个View的话,还需要增加几个属性:
然后在viewDidLoad方法里增加对“钩子”的处理:
只有当状态为开始或结束的时候我们才需要更新UI状态,而且我们在结束的事件里延迟了1秒钟,这样用户可以暂时预览下全图。
依靠Auto Layout布局系统以及我们在钩子里对高度的处理,用户在设置页面绘图时也能完美运行。
最后一个功能:保存到图库!
在toolbar上插入一个title为“保存到图库”的
我为
然后是一个方法指针的回调:
旅行到终点了~!
看了下,有些小长,文本+代码有2w3+,全部代码去除空行和空格有1w4+,直接贴代码会简单很多,但我始终觉得让代码完成功能并不是全部目的,代码背后隐藏的问题定义、设计、构建更有意义,毕竟软件开发完成“后”比完成“前”所花费的时间永远更多(除非是一个只有10行代码或者“一次性”的程序)。
希望与大家多多交流。
最后吐槽下CSDN新的Markdown编辑器,代码样式丑且不能自定义,而且有些代码高亮都无法识别。不过感觉草稿箱比以前更方便,问题主要还是集中在样式上,希望以后能不断改进,会一如既往的支持。
DrawingBoard
要做一个全功能的绘图板,至少要支持以下这些功能:
支持铅笔绘图(画点)
支持画直线
支持一些简单的图形(矩形、圆形等)
做一个真正的橡皮擦
能设置画笔的粗细
能设置画笔的颜色和填充颜色
能设置背景色或者背景图
…
我们先做一些基础性的工作,比如创建工程。
工程搭建
先创建一个Single View Application工程:
语言选择
Swift:
为了最大程度的利用屏幕区域,我们完全隐藏掉状态栏,在
Info.plist里修改或添加这两个参数:
然后进入到
Main.storyboard,开始搭建我们的UI。
我们给已存在的
ViewController的
View添加一个
UIImageView的子视图,背景色设为
Light Gray,然后添加4个约束,由于要做一个全屏的画板,必须要让
Constraint to margins保持没有选中的状态,否则左右两边会留下苹果建议的空白区域:
然后我们回到
ViewController的
View上:
添加一个放工具栏的容器:
UIView,为该View设置约束:
同样的不要选择
Contraint to margins。
在该View里添加一个
UISegmentedControl,并给SegmentedControl设置6个选项,分别是:
铅笔
直尺
虚线
矩形
圆形
橡皮擦
给这个SegmentedControl添加约束:
垂直居中,两边各留20,高度固定为28。
完整的UI及结构看起来像这样:
ImageView将会作为实际的绘制区域,顶部的SegmentedControl提供工具的选择。 到目前为止我们还没有写下一行代码,至此要开始编码了。
你可能会注意到Board有一部分被挡住了,这只是暂时的~
施工…
Board
我们创建一个Board类,继承自
UIImageView,同时把这个类设置为
Main.storyboard中
ImageView的Class,这样当app启动的时候就会自动创建一个Board的实例了。
增加两个属性以及初始化方法:
<code class="language-swift hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">var strokeWidth: <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">CGFloat</span> var strokeColor: <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIColor</span> override init() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.strokeColor</span> = <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIColor</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.blackColor</span>() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.strokeWidth</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.init</span>() } required init(coder aDecoder: NSCoder) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.strokeColor</span> = <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIColor</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.blackColor</span>() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.strokeWidth</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.init</span>(coder: aDecoder) }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>
由于我们是依赖于touches方法来完成绘图过程,我们需要记录下每次touch的状态,比如
began、
moved、
ended等,为此我们创建一个枚举,在touches方法中进行记录,并调用私有的绘图方法
drawingImage:
<code class="language-swift hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">enum</span> DrawingState { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">case</span> Began, Moved, Ended } class Board: UIImageView { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> drawingState: DrawingState! // 此处省略init方法与另外两个属性 // MARK: - touches methods <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">override</span> func <span class="hljs-title" style="box-sizing: border-box;">touchesBegan</span>(touches: NSSet, withEvent <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>: UIEvent) { self.drawingState = .Began self.drawingImage() } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">override</span> func touchesMoved(touches: NSSet, withEvent <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>: UIEvent) { self.drawingState = .Moved self.drawingImage() } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">override</span> func touchesEnded(touches: NSSet, withEvent <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">event</span>: UIEvent) { self.drawingState = .Ended self.drawingImage() } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// MARK: - drawing</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> func <span class="hljs-ti 20000 tle" style="box-sizing: border-box;">drawingImage</span>() { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 暂时为空实现</span> } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li></ul>
在我们实现drawingImage方法之前,我们先创建另外一个重要的组件:
BaseBrush。
BaseBrush
顾名思义,BaseBrush将会作为一个绘图的基类而存在,我们会在它的基础上创建一系列的子类,以达到弹性的设计目的。为此,我们创建一个
BaseBrush类,并实现一个
PaintBrush接口:
<code class="language-swift hljs go has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> CoreGraphics protocol PaintBrush { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">func</span> supportedContinuousDrawing() -> Bool; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">func</span> drawInContext(context: CGContextRef) } class BaseBrush : NSObject, PaintBrush { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> beginPoint: CGPoint! <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> endPoint: CGPoint! <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> lastPoint: CGPoint? <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> strokeWidth: CGFloat! <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">func</span> supportedContinuousDrawing() -> Bool { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-constant" style="box-sizing: border-box;">false</span> } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">func</span> drawInContext(context: CGContextRef) { assert(<span class="hljs-constant" style="box-sizing: border-box;">false</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"must implements in subclass."</span>) } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li></ul>
BaseBrush实现了
PaintBrush接口,
PaintBrush声明了两个方法:
supportedContinuousDrawing,表示是否是连续不断的绘图
drawInContext,基于Context的绘图方法,子类必须实现具体的绘图
只要是实现了
PaintBrush接口的类,我们就当作是一个绘图工具(如铅笔、直尺等),而
BaseBrush除了实现
PaintBrush接口以外,我们还为它增加了四个便利属性:
beginPoint,开始点的位置
endPoint,结束点的位置
lastPoint,最后一个点的位置(也可以称作是上一个点的位置)
strokeWidth,画笔的宽度
这么一来,子类也可以很方便的获取到当前的状态,并作一些深度定制的绘图方法。
回到Board
我们实现了一个画笔的基类之后,就可以重新回到Board类了,毕竟我们之前的工作还没有做完,现在是时候完善
Board类了。
我们用
Board实际操纵
BaseBrush,先为
Board添加两个新的属性:
<code class="language-swift hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> brush: BaseBrush? <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> realImage: UIImage? </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>
brush对应到具体的画笔类,
realImage保存当前的图形,重新修改touches方法,以便增加对
brush属性的处理,完整的touches方法实现如下:
<code class="language-swift hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">// MARK: - touches methods override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { if let brush = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.brush</span> { brush<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lastPoint</span> = nil brush<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.beginPoint</span> = touches<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.anyObject</span>()!<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.locationInView</span>(self) brush<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.endPoint</span> = brush<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.beginPoint</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.drawingState</span> = <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Began</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.drawingImage</span>() } } override func touchesMoved(touches: NSSet, withEvent event: UIEvent) { if let brush = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.brush</span> { brush<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.endPoint</span> = touches<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.anyObject</span>()!<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.locationInView</span>(self) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.drawingState</span> = <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Moved</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.drawingImage</span>() } } override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) { if let brush = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.brush</span> { brush<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.endPoint</span> = nil } } override func touchesEnded(touches: NSSet, withEvent event: UIEvent) { if let brush = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.brush</span> { brush<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.endPoint</span> = touches<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.anyObject</span>()!<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.locationInView</span>(self) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.drawingState</span> = <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Ended</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.drawingImage</span>() } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li></ul>
我们需要防止
brush为
nil的情况,以及为
brush设置好
beginPoint和
endPoint,之后我们就可以完善
drawingImage方法了,实现如下:
<code class="language-swift hljs lasso has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> func drawingImage() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">let</span> brush <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">self</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>brush { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 1.</span> UIGraphicsBeginImageContext(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">self</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>bounds<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>size) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">let</span> context <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> UIGraphicsGetCurrentContext() UIColor<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>clearColor()<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>setFill() UIRectFill(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">self</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>bounds) CGContextSetLineCap(context, kCGLineCapRound) CGContextSetLineWidth(context, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">self</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>strokeWidth) CGContextSetStrokeColorWithColor(context, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">self</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>strokeColor<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>CGColor) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 3.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">let</span> realImage <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">self</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>realImage { realImage<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>drawInRect(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">self</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>bounds) } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 4.</span> brush<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>strokeWidth <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">self</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>strokeWidth brush<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>drawInContext(context); CGContextStrokePath(context) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 5.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">let</span> previewImage <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> UIGraphicsGetImageFromCurrentImageContext() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">self</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>drawingState <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">==</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>Ended <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">||</span> brush<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>supportedContinuousDrawing() { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">self</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>realImage <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> previewImage } UIGraphicsEndImageContext() <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 6.</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">self</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>image <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> previewImage; brush<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>lastPoint <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> brush<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>endPoint } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li></ul>
步骤解析:
开启一个新的ImageContext,为保存每次的绘图状态作准备。
初始化context,进行基本设置(画笔宽度、画笔颜色、画笔的圆润度等)。
把之前保存的图片绘制进context中。
设置
brush的基本属性,以便子类更方便的绘图;调用具体的绘图方法,并最终添加到context中。
从当前的context中,得到Image,如果是
ended状态或者需要支持连续不断的绘图,则将Image保存到
realImage中。
实时显示当前的绘制状态,并记录绘制的最后一个点。
这些工作完成以后,我们就可以开始写第一个工具了:铅笔工具。
铅笔工具
铅笔工具应该支持连续不断的绘图(不断的保存到realImage中),这也是我们给PaintBrush接口增加
supportedContinuousDrawing方法的原因,考虑到用户的手指可能快速的移动,导致从一个点到另一个点有着跳跃性的动作,我们对铅笔工具采用画直线的方式来实现。
首先创建一个类,名为
PencilBrush,继承自
BaseBrush类,实现如下:
<code class="language-swift hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">class PencilBrush: BaseBrush { override func drawInContext(context: CGContextRef) { if let lastPoint = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lastPoint</span> { CGContextMoveToPoint(context, lastPoint<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.x</span>, lastPoint<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.y</span>) CGContextAddLineToPoint(context, endPoint<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.x</span>, endPoint<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.y</span>) } else { CGContextMoveToPoint(context, beginPoint<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.x</span>, beginPoint<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.y</span>) CGContextAddLineToPoint(context, endPoint<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.x</span>, endPoint<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.y</span>) } } override func supportedContinuousDrawing() -> Bool { return true } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>
如果lastPoint为nil,则基于beginPoint画线,反之则基于lastPoint画线。
这样一来,一个铅笔工具就完成了,怎么样,很简单吧。
测试
到目前为止,我们的ViewController还保持着默认的状态,是时候先为铅笔工具写一些测试代码了。
在
ViewController添加
board属性,并与
Main.storyboard中的Board关联起来;创建一个
brushes属性,并为之赋值为:
<code class="language-swift hljs fix has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-attribute" style="box-sizing: border-box;">var brushes </span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"> [PencilBrush()]</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
在
ViewController中添加
switchBrush:方法,并把
Main.storyboard中的SegmentedControl的
ValueChanged连接到
ViewController的
switchBrush:方法上,实现如下:
<code class="language-swift hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">@IBAction func switchBrush(sender: UISegmentedControl) { assert(sender<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.tag</span> < self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.brushes</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.count</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"!!!"</span>) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.board</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.brush</span> = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.brushes</span>[sender<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.selectedSegmentIndex</span>] }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>
最后在
viewDidLoad方法中做一个初始化:
self.board.brush = brushes[0]
编译、运行,铅笔工具可以完美运行~!
其他的工具
接下来我们把其他的绘图工具也实现了。其他的工具不像铅笔工具,不需要支持连续不断的绘图,所以也就不用覆盖
supportedContinuousDrawing方法了。
直尺
创建一个LineBrush类,实现如下:
<code class="language-swift hljs haskell has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">LineBrush</span>: <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">BaseBrush</span> { override func drawInContext<span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">context</span>: <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGContextRef</span>)</span> { <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGContextMoveToPoint</span><span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">context</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">beginPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">x</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">beginPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">y</span>)</span> <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGContextAddLineToPoint</span><span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">context</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">endPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">x</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">endPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">y</span>)</span> } }</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
虚线
创建一个DashLineBrush类,实现如下:
<code class="language-swift hljs haskell has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">DashLineBrush</span>: <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">BaseBrush</span> { override func drawInContext<span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">context</span>: <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGContextRef</span>)</span> { let lengths: [<span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGFloat</span>] = [self.strokeWidth * 3, self.strokeWidth * 3] <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGContextSetLineDash</span><span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">context</span>, 0, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">lengths</span>, 2)</span>; <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGContextMoveToPoint</span><span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">context</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">beginPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">x</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">beginPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">y</span>)</span> <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGContextAddLineToPoint</span><span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">context</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">endPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">x</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">endPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">y</span>)</span> } }</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>
这里我们就用到了
BaseBrush的
strokeWidth属性,因为我们想要创建一条动态的虚线。
矩形
创建一个RectangleBrush类,实现如下:
<code class="language-swift hljs haskell has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">RectangleBrush</span>: <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">BaseBrush</span> { override func drawInContext<span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">context</span>: <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGContextRef</span>)</span> { <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGContextAddRect</span><span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">context</span>, <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGRect</span>(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">origin</span>: <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGPoint</span>(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">x</span>: <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">min</span>(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">beginPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">x</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">endPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">x</span>)</span>, y: min<span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">beginPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">y</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">endPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">y</span>)</span>), size: <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGSize</span><span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">width</span>: <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">abs</span>(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">endPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">x</span> - <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">beginPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">x</span>)</span>, height: abs<span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">endPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">y</span> - <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">beginPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">y</span>)</span>))) } }</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
我们用到了一些计算,因为我们希望矩形的区域不是由beginPoint定死的。
圆形
创建一个EllipseBrush类,实现如下:
<code class="language-swift hljs haskell has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">EllipseBrush</span>: <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">BaseBrush</span> { override func drawInContext<span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">context</span>: <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGContextRef</span>)</span> { <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGContextAddEllipseInRect</span><span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">context</span>, <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGRect</span>(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">origin</span>: <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGPoint</span>(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">x</span>: <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">min</span>(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">beginPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">x</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">endPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">x</span>)</span>, y: min<span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">beginPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">y</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">endPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">y</span>)</span>), size: <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGSize</span><span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">width</span>: <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">abs</span>(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">endPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">x</span> - <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">beginPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">x</span>)</span>, height: abs<span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">endPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">y</span> - <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">beginPoint</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">y</span>)</span>))) } }</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
同样有一些计算,理由同上。
橡皮擦
从本文一开始就说过了,我们要做一个真正的橡皮擦,网上有很多的橡皮擦的实现其实就是把画笔颜色设置为背景色,但是如果背景色可以动态设置,甚至设置为一个渐变的图片时,这种方法就失效了,所以有些绘图app的背景色就是固定为白色的。其实Apple的Quartz2D框架本身就是支持橡皮擦的,只用一个方法就可以完美实现。
让我们创建一个
EraserBrush类,实现如下:
<code class="language-swift hljs haskell has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">EraserBrush</span>: <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">PencilBrush</span> { override func drawInContext<span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">context</span>: <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGContextRef</span>)</span> { <span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">CGContextSetBlendMode</span><span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">context</span>, <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">kCGBlendModeClear</span>)</span>; super.drawInContext<span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">context</span>)</span> } }</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>
注意,与其他的工具不同,橡皮擦是继承自
PencilBrush的,因为橡皮擦本身也是基于点的,而
drawInContext里也只是加了一句:
<code class="language-swift hljs vhdl has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">CGContextSetBlendMode(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">context</span>, kCGBlendModeClear);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
加入这一句代码,一个真正的橡皮擦便实现了。
再次测试
现在我们的工程结构应该类似于这样:我们修改下
ViewController中的
brushes属性的初始值:
<code class="language-swift hljs fix has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-attribute" style="box-sizing: border-box;">var brushes </span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"> [PencilBrush(), LineBrush(), DashLineBrush(), RectangleBrush(), EllipseBrush(), EraserBrush()]</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
编译、运行:
除了橡皮擦擦除的范围太小以外,一切都很完美~!
设计思路
在继续完成剩下的功能之前,我想先对之前的代码进行些说明。
为什么不用drawRect方法
其实我最开始也是使用drawRect方法来完成绘制,但是感觉限制很多,比如context无法保存,还是要每次重画(虽然可以保存到一个BitMapContext里,但是这样与保存到image里有什么区别呢?);后来用CALayer保存每一条CGPath,但是这样仍然不能避免每次重绘,因为需要考虑到橡皮擦和画笔属性之类的影响,这么一来还不如采用image的方式来保存最新绘图板。既然定下了以image来保存绘图板,那么drawRect就不方便了,因为不能用
UIGraphicsBeginImageContext方法来创建一个ImageContext。
ViewController与Board、BaseBrush之间的关系
在ViewController、
Board和
BaseBrush这三者之间,虽然VC要知道另外两个组件,但是仅限于选择对应的工具给Board,Board本身并不知道当前的brush是哪个brush,也不需要知道其内部实现,只管调用对应的brush就行了;BaseBrush(及其子类)也并不知道自己将会被用于哪,它们只需要实现自己的算法即可。类似于这样的图:
实际上这里包含了两个设计模式。
策略设计模式
策略设计模式的UML图:
策略设计模式在iOS中也应用广泛,如
AFNetworking的
AFHTTPRequestSerializer和
AFHTTPResponseSerializer的设计,通过在运行时动态的改变委托对象,变换行为,使程序模块之间解耦、提高应变能力。
以我们的绘图板为例,输出不同的图形就意味着不同的算法,用户可根据不同的需求来选择某一种算法,即BaseBrush及其子类做具体的封装,这样的好处是每一个子类只关心自己的算法,达到了高聚合的原则,高级模块(Board)不用关心具体实现,最终我们实现了一个好维护、易拓展的程序(妈妈再也不用担心工具栏不够用了^^)。
策略模式的定义:定义一个算法群,把每一个算法分别封装起来,让它们之间可以互相替换,使算法的变化独立于使用它的用户之上。
模板方法
在传统的策略模式中,每一个算法类都独自完成整个算法过程,而我们将BaseBrush的角色提升为算法的基类,并提供一些便利的属性,再通过
drawingImage方法调用
BaseBrush的接口,搭建了算法的骨架。
模板方法的UML图:
图中右边的方框代表模板方法。
BaseBrush通过提供抽象方法(
drawInContext)、具体方法或钩子方法(
supportedContinuousDrawing)来对应算法的每一个步骤,让其子类可以重定义或实现这些步骤。同时,让模板方法(即
dawingImage)定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法。
模板方法的定义:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
以上就是我设计时的思路,说完了,接下来还要完成的工作有:
提供对画笔颜色、粗细的设置
背景设置
全屏绘图(不能让Board一直显示不全)
先从画笔开始,Let’s go!
画笔设置
不管是画笔还是背景设置,我们都要有一个能提供设置的工具栏。
设置工具栏
所以我们往Board上再盖一个
UIToolbar,与顶部的View类似:
拖一个
UIToolbar到
Board的父类上,与
Board的视图层级平级。
设置
UIToolbar的约束:左、右、下间距为0,高为44:
往
UIToolbar上拖一个
UIBarButtonItem,
title就写:画笔设置。
在
ViewController里增加一个
paintingBrushSettings方法,并把
UIBarButtonItem的
action连接
paintingBrushSettings方法上。
在
ViewController里增加一个
toolar属性,并把Xib中的
UIToolbar连接到
toolbar上。
UIToolbar配置好后,UI及视图层级如下:
RGBColorPicker
考虑到多个页面需要选取自定义的颜色,我们先创建一个工具类:RGBColorPicker,用于选择RGB颜色:
<code class="language-swift hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">class RGBColorPicker: UIView { var colorChangedBlock: ((color: UIColor) -> Void)? private var sliders = [UISlider]() private var labels = [UILabel]() override init(frame: CGRect) { super<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.init</span>(frame: frame) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.initial</span>() } required init(coder aDecoder: NSCoder) { super<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.init</span>(coder: aDecoder) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.initial</span>() } private func initial() { self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.backgroundColor</span> = UIColor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.clearColor</span>() let trackColors = [UIColor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.redColor</span>(), UIColor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.greenColor</span>(), UIColor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.blueColor</span>()] for index <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.</span>.<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">.3</span> { let slider = UISlider() slider<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.minimumValue</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> slider<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.value</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> slider<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.maximumValue</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">255</span> slider<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.minimumTrackTintColor</span> = trackColors[index - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] slider<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addTarget</span>(self, action: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"colorChanged:"</span>, forControlEvents: <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ValueChanged</span>) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addSubview</span>(slider) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sliders</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.append</span>(slider) let label = UILabel() label<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.text</span> = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"0"</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addSubview</span>(label) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.labels</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.append</span>(label) } } override func layoutSubviews() { super<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.layoutSubviews</span>() let sliderHeight = CGFloat(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">31</span>) let labelWidth = CGFloat(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">29</span>) let yHeight = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.bounds</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.size</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.height</span> / CGFloat(sliders<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.count</span>) for index <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.</span>.<self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sliders</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.count</span> { let slider = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sliders</span>[index] slider<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.frame</span> = CGRect(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">x</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">y</span>: CGFloat(index) * yHeight, width: self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.bounds</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.size</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.width</span> - labelWidth - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5.0</span>, height: sliderHeight) let label = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.labels</span>[index] label<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.frame</span> = CGRect(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">x</span>: CGRectGetMaxX(slider<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.frame</span>) + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">y</span>: slider<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.frame</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.origin</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.y</span>, width: labelWidth, height: sliderHeight) } } override func intrinsicContentSize() -> CGSize { return CGSize(width: UIViewNoIntrinsicMetric, height: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">107</span>) } @IBAction private func colorChanged(slider: UISlider) { let color = UIColor( red: CGFloat(self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sliders</span>[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.value</span> / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">255.0</span>), green: CGFloat(self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sliders</span>[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.value</span> / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">255.0</span>), blue: CGFloat(self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sliders</span>[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>]<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.value</span> / <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">255.0</span>), alpha: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) let label = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.labels</span>[find(self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sliders</span>, slider)!] label<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.text</span> = NSString(format: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%.0f"</span>, slider<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.value</span>) if let colorChangedBlock = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.colorChangedBlock</span> { colorChangedBlock(color: color) } } func setCurrentColor(color: UIColor) { var red: CGFloat = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, green: CGFloat = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, blue: CGFloat = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> color<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getRed</span>(&red, green: &green, blue: &blue, alpha: nil) let colors = [red, green, blue] for index <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.</span>.<self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sliders</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.count</span> { let slider = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sliders</span>[index] slider<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.value</span> = Float(colors[index]) * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">255</span> let label = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.labels</span>[index] label<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.text</span> = NSString(format: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%.0f"</span>, slider<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.value</span>) } } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 4000 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li></ul>
这个工具类很简单,没有采用Auto Layout进行布局,因为
layoutSubviews方法已经能很好的满足我们的需求了。当用户拖动任何一个
UISlider的时候,我们能实时的通过
colorChangedBlock回调给外部。它能展现一个这样的视图:
不过虽然该工具类本身没有采用Auto Layout进行布局,但是它还是支持Auto Layout的,当它被添加到某个Auto Layout的视图中的时候,Auto Layout布局系统可以通过
intrinsicContentSize知道该视图的尺寸信息。
最后它还有一个
setCurrentColor方法从外部接收一个UIColor,可以用于初始化。
画笔设置的UI
我打算在用户点击画笔设置的时候,从底部弹出一个控制面板(就像系统的
Control Center那样),所以我们还要有一个像这样的设置UI:
具体的,创建一个
PaintingBrushSettingsView类,同时创建一个
PaintingBrushSettingsView.xib文件,并把xib中view的
Class设为
PaintingBrushSettingsView,设置view的背景色为透明:
放置一个title为“画笔粗细”的
UILabel,约束设为:宽度固定为68,高度固定为21,左和上边距为8。
放置一个title为“1”的
UILabel,“1”与“画笔粗细”的垂直间距为10,宽度固定为10,高度固定为21,与
superview的左边距为10。
放置一个
UISlider,用于调节画笔的粗细,与“1”的水平间距为5,并与“1”垂直居中,高度固定为30,宽度暂时不设,在
PaintingBrushSettingsView中添加
strokeWidthSlider属性,与之连接起来。
放置一个title为“20”的
UILabel,约束设为:宽度固定为20,高度固定为21,top与“1”相同,与
superview的右间距为10。并把上一步中的
UISlider的右间距设为与“20”相隔5。
放置一个title为“画笔颜色”的
UILabel,宽、高、left与“画笔粗细”相同,与上面
UISlider的垂直间距设为12。
放置一个
UIView至“画笔颜色”下方(上图中被选中的那个UIView),宽度固定为50,高度固定为30,left与“画笔颜色”相同,并且与“画笔颜色”的垂直间距为5,在
PaintingBrushSettingsView中添加
strokeColorPreview属性,与之连接起来。
放置一个
RGBColorPicker,约束设为:left与顶部的UISlider相同,底部与superview的间距为0,右间距为10,与上一步中的UIView的垂直间距为5。
PaintingBrushSettingsView类的完整代码如下:
<code class="language-swift hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">class PaintingBrushSettingsView : UIView { var strokeWidthChangedBlock: ((strokeWidth: CGFloat) -> Void)? var strokeColorChangedBlock: ((strokeColor: UIColor) -> Void)? @IBOutlet private var strokeWidthSlider: UISlider! @IBOutlet private var strokeColorPreview: UIView! @IBOutlet private var colorPicker: RGBColorPicker! override func awakeFromNib() { super<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.awakeFromNib</span>() self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.strokeColorPreview</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.layer</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.borderColor</span> = UIColor<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.blackColor</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.CGColor</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.strokeColorPreview</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.layer</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.borderWidth</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.colorPicker</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.colorChangedBlock</span> = { [unowned self] (color: UIColor) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.strokeColorPreview</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.backgroundColor</span> = color if let strokeColorChangedBlock = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.strokeColorChangedBlock</span> { strokeColorChangedBlock(strokeColor: color) } } self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.strokeWidthSlider</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addTarget</span>(self, action: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"strokeWidthChanged:"</span>, forControlEvents: <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ValueChanged</span>) } func setBackgroundColor(color: UIColor) { self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.strokeColorPreview</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.backgroundColor</span> = color self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.colorPicker</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setCurrentColor</span>(color) } func strokeWidthChanged(slider: UISlider) { if let strokeWidthChangedBlock = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.strokeWidthChangedBlock</span> { strokeWidthChangedBlock(strokeWidth: CGFloat(slider<span class="hljs-preprocessor" style="color: 263e0 rgb(68, 68, 68); box-sizing: border-box;">.value</span>)) } } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li></ul>
strokeWidthChangedBlock和
strokeColorChangedBlock两个Block用于给外部传递状态。
setBackgroundColor用于初始化。
实现毛玻璃效果
在把PaintingBrushSettingsView显示出来之前,我们要先想一想以何种方式展现比较好,众所周知
Control Center是有毛玻璃效果的,我们也想要这样的效果,而且不用自己实现。那如何产生效果? 答案是用
UIToolbar就行了。
UIToolbar本身就是带有毛玻璃效果的,只要你不设置背景色,并且
translucent属性为true,“恰好”我们页面底部就有一个
UIToolbar,我们把它拉高就可以插入展现
PaintingBrushSettingsView了。
只要get到了这一点,毛玻璃效果就算实现了~~
测试画笔设置
我们在ViewController新增加几个属性:<code class="language-swift hljs scala has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> toolbarEditingItems: [UIBarButtonItem]? <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> currentSettingsView: UIView? <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@IBOutlet</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> toolbarConstraintHeight: NSLayoutConstraint!</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
toolbarConstraintHeight连接到
Main.storyboard中对应的约束上就行了。
toolbarEditingItems能让我们在
UIToolbar上显示不同的
items,本来还需要一个
toolbarItems属性的,因为
UIViewController类本身就自带,我们便不用单独新增。
currentSettingsView是用来保存当前展示的哪个设置页面,考虑到我们后面会增加
背景设置,这个属性还是有必要的。
我们先写一个往toolbar上添加约束的工具方法:
<code class="language-swift hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">func addConstraintsToToolbarForSettingsView(view: UIView) { view<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setTranslatesAutoresizingMaskIntoConstraints</span>(false) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.toolbar</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addSubview</span>(view) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.toolbar</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addConstraints</span>(NSLayoutConstraint<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.constraintsWithVisualFormat</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"H:|-0-[settingsView]-0-|"</span>, options: <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.DirectionLeadingToTrailing</span>, metrics: nil, views: [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"settingsView"</span> : view])) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.toolbar</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addConstraints</span>(NSLayoutConstraint<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.constraintsWithVisualFormat</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"V:|-0-[settingsView(==height)]"</span>, options: <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.DirectionLeadingToTrailing</span>, metrics: [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"height"</span> : view<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.systemLayoutSizeFittingSize</span>(UILayoutFittingCompressedSize)<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.height</span>], views: [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"settingsView"</span> : view])) }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>
这个工具方法会把传入进来的view添加到toolbar上,同时添加相应的约束。注意高度的约束,我是通过
systemLayoutSizeFittingSize方法计算出设置视图最佳的高度,这是为了达到更好的拓展性(背景设置与画笔设置所需要的高度很可能会不同)。
然后再增加一个
setupBrushSettingsView方法:
<code class="language-swift hljs http has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"> <span class="avrasm" style="box-sizing: border-box;">func setupBrushSettingsView() { let brushSettingsView = UINib(nibName: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"PaintingBrushSettingsView"</span>, bundle: nil)<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.instantiateWithOwner</span>(nil, options: nil)<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.first</span> as PaintingBrushSettingsView self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addConstraintsToToolbarForSettingsView</span>(brushSettingsView) brushSettingsView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.hidden</span> = true brushSettingsView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.tag</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> brushSettingsView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setBackgroundColor</span>(self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.board</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.strokeColor</span>) brushSettingsView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.strokeWidthChangedBlock</span> = { [unowned self] (strokeWidth: CGFloat) -> Void <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.board</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.strokeWidth</span> = strokeWidth } brushSettingsView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.strokeColorChangedBlock</span> = { [unowned self] (strokeColor: UIColor) -> Void <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.board</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.strokeColor</span> = strokeColor } }</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul>
我们在这个方法里实例化了一个
PaintingBrushSettingsView,并添加到toolbar上,增加相应的约束,以及一些初始化设置和两个Block回调的处理。
然后修改
viewDidLoad方法,增加以下行为:
<code class="language-swift hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//---</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.toolbarEditingItems</span> = [ <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIBarButtonItem</span>(barButtonSystemItem:<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.FlexibleSpace</span>, target: <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>, action: <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>), <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIBarButtonItem</span>(title: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"完成"</span>, style:<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.Plain</span>, target: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>, action: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"endSetting"</span>) ] <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.toolbarItems</span> = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.toolbar</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.items</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.setupBrushSettingsView</span>() <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//---</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>
在
paintingBrushSettings方法里响应点击:
<code class="language-swift hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">@IBAction func paintingBrushSettings() { self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.currentSettingsView</span> = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.toolbar</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.viewWithTag</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.currentSettingsView</span>?<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.hidden</span> = false self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.updateToolbarForSettingsView</span>() } func updateToolbarForSettingsView() { self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.toolbarConstraintHeight</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.constant</span> = self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.currentSettingsView</span>!<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.systemLayoutSizeFittingSize</span>(UILayoutFittingCompressedSize)<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.height</span> + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">44</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.toolbar</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setItems</span>(self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.toolbarEditingItems</span>, animated: true) UIView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.beginAnimations</span>(nil, context: nil) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.toolbar</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.layoutIfNeeded</span>() UIView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.commitAnimations</span>() self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.toolbar</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.bringSubviewToFront</span>(self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.currentSettingsView</span>!) }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>
updateToolbarForSettingsView也是一个工具方法,用于更新toolbar的高度。
由于我们采用了Auto Layout进行布局,动画要通过调用
layoutIfNeeded方法来实现。
响应点击“完成”按钮的
endSetting方法:
<code class="language-swift hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">@IBAction func endSetting() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.toolbarConstraintHeight</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.constant</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">44</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.toolbar</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.setItems</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.toolbarItems</span>, animated: <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">true</span>) <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIView</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.beginAnimations</span>(<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>, context: <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.toolbar</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.layoutIfNeeded</span>() <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIView</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.commitAnimations</span>() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.currentSettingsView</span>?<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.hidden</span> = <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">true</span> }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>
这么一来画笔设置就做完了,代码应该还是比较好理解,编译、运行后,应该能看到:
完成度已经很高了^^!
背景设置
整体的框架基本上已经在之前的工作中搭好了,我们快速过掉这一节。在
Main.storyboard中增加了一个title为“背景设置”的
UIBarButtonItem,并将action连接到
ViewController的
backgroundSettings方法上,你可以选择在插入“背景设置”之前,先插入一个
FlexibleSpace的
UIBarButtonItem。
创建
BackgroundSettingsVC类,继承自
UIViewController,这与画笔设置继承于
UIView不同,我们希望背景设置可以在用户的相册中选择照片,而使用
UIImagePickerController的前提是要实现
UIImagePickerControllerDelegate、
UINavigationControllerDelegate两个接口,如果让UIView来实现这两个接口会很奇怪。
创建一个
BackgroundSettingsVC.xib文件:
放置一个title为“从相册中选择背景图”的UIButton,约束为:左、上边距为8,宽度固定为135,高度固定为30。
放置一个RGBColorPicker,约束为:左、右边距为8,与UIButton的垂直间距为20,底部与superview齐平。
把UIButton的
Touch Up Inside事件连接到
BackgroundSettingsVC的
pickImage方法上;RGBColorPicker连接到
BackgroundSettingsVC的
colorPicker属性上。
看上去像这样:
BackgroundSettingsVC类的完整代码:
<code class="language-swift hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">class BackgroundSettingsVC : <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIViewController</span>, UIImagePickerControllerDelegate, UINavigationControllerDelegate { var backgroundImageChangedBlock: ((backgroundImage: <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIImage</span>) -> Void)? var backgroundColorChangedBlock: ((backgroundColor: <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIColor</span>) -> Void)? @IBOutlet private var colorPicker: RGBColorPicker! lazy private var pickerController: UIImagePickerController = { [unowned <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>] in let pickerController = UIImagePickerController() pickerController<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.delegate</span> = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> pickerController }() override func awakeFromNib() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.awakeFromNib</span>() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.colorPicker</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.colorChangedBlock</span> = { [unowned <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>] (color: <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIColor</span>) in <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> let backgroundColorChangedBlock = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.backgroundColorChangedBlock</span> { backgroundColorChangedBlock(backgroundColor: color) } } } func setBackgroundColor(color: <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIColor</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.colorPicker</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.setCurrentColor</span>(color) } @IBAction func pickImage() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.presentViewController</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.pickerController</span>, animated: <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">true</span>, completion: <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>) } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// MARK: UIImagePickerControllerDelegate Methods</span> func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSObject</span> : AnyObject]) { let image = info[UIImagePickerControllerOriginalImage] as <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIImage</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> let backgroundImageChangedBlock = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.backgroundImageChangedBlock</span> { backgroundImageChangedBlock(backgroundImage: image) } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.dismissViewControllerAnimated</span>(<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">true</span>, completion: <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>) } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// MARK: UINavigationControllerDelegate Methods</span> func navigationController(navigationController: <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UINavigationController</span>, willShowViewController viewController: <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIViewController</span>, animated: Bool) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIApplication</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.sharedApplication</span>()<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.setStatusBarHidden</span>(<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">true</span>, withAnimation: <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.None</span>) } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li></ul>
同样用两个Block进行回调;
setBackgroundColor公共方法用于设置内部的RGBColorPicker的初始颜色状态;在
UINavigationControllerDelegate里隐藏系统默认显示的状态栏。
回到
ViewController,我们对背景设置进行测试。
像
setupBrushSettingsView方法一样,我们增加一个
setupBackgroundSettingsView方法:
<code class="language-swift hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">func setupBackgroundSettingsView() { let backgroundSettingsVC = UINib(nibName: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"BackgroundSettingsVC"</span>, bundle: nil)<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.instantiateWithOwner</span>(nil, options: nil)<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.first</span> as BackgroundSettingsVC self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addConstraintsToToolbarForSettingsView</span>(backgroundSettingsVC<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.view</span>) backgroundSettingsVC<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.view</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.hidden</span> = true backgroundSettingsVC<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.view</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.tag</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span> backgroundSettingsVC<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setBackgroundColor</span>(self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.board</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.backgroundColor</span>!) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addChildViewController</span>(backgroundSettingsVC) backgroundSettingsVC<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.backgroundImageChangedBlock</span> = { [unowned self] (backgroundImage: UIImage) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.board</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.backgroundColor</span> = UIColor(patternImage: backgroundImage) } backgroundSettingsVC<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.backgroundColorChangedBlock</span> = { [unowned self] (backgroundColor: UIColor) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.board</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.backgroundColor</span> = backgroundColor } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul>
修改viewDidLoad方法:
<code class="language-swift hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.toolbarEditingItems</span> = [ <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIBarButtonItem</span>(barButtonSystemItem:<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.FlexibleSpace</span>, target: <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>, action: <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>), <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIBarButtonItem</span>(title: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"完成"</span>, style:<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.Plain</span>, target: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>, action: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"endSetting"</span>) ] <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.toolbarItems</span> = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.toolbar</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.items</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.setupBrushSettingsView</span>() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.setupBackgroundSettingsView</span>() <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Added~!!!</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>
实现
backgroundSettings方法:
<code class="language-swift hljs ruby has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">@IBAction</span> func backgroundSettings() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>.currentSettingsView = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>.toolbar.viewWithTag(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>.currentSettingsView?.hidden = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>.updateToolbarForSettingsView() }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>
编译、运行,现在你可以用不同的背景色(或背景图)了!
全屏绘图
到目前为止,Board一直显示不全(事实上,我很早就实现了全屏绘图,但是优先级一直被我排在最后
),现在是时候来解决它了。
解决思路是这样的:当用户开始绘图的时候,我们把顶部和底部两个View隐藏;当用户结束绘图的时候,再让两个View显示。
为了获取用户的绘图状态,我们需要在
Board里加个“钩子”:
<code class="language-swift hljs lasso has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 增加一个Block回调</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">var</span> drawingStateChangedBlock: ((state: DrawingState) <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-> </span>())<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">?</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> func drawingImage() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">let</span> brush <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">self</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>brush { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// hook</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">let</span> drawingStateChangedBlock <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">self</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>drawingStateChangedBlock { drawingStateChangedBlock(state: <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">self</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>drawingState) } UIGraphicsBeginImageContext(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">self</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>bounds<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>size) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ...</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>
这样一来用户绘图的状态就在ViewController掌握中了。
ViewController想要控制两个View的话,还需要增加几个属性:
<code class="language-swift hljs scala has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@IBOutlet</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> topView: UIView! <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@IBOutlet</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> topViewConstraintY: NSLayoutConstraint! <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@IBOutlet</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> toolbarConstraintBottom: NSLayoutConstraint!</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>
然后在viewDidLoad方法里增加对“钩子”的处理:
<code class="language-swift hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.board</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.drawingStateChangedBlock</span> = {(state: DrawingState) -> () <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> if state != <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Moved</span> { UIView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.beginAnimations</span>(nil, context: nil) if state == <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Began</span> { self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.topViewConstraintY</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.constant</span> = -self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.topView</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.frame</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.size</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.height</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.toolbarConstraintBottom</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.constant</span> = -self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.toolbar</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.frame</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.size</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.height</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.topView</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.layoutIfNeeded</span>() self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.toolbar</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.layoutIfNeeded</span>() } else if state == <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Ended</span> { UIView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setAnimationDelay</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.0</span>) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.topViewConstraintY</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.constant</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.toolbarConstraintBottom</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.constant</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.topView</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.layoutIfNeeded</span>() self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.toolbar</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.layoutIfNeeded</span>() } UIView<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.commitAnimations</span>() } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li></ul>
只有当状态为开始或结束的时候我们才需要更新UI状态,而且我们在结束的事件里延迟了1秒钟,这样用户可以暂时预览下全图。
依靠Auto Layout布局系统以及我们在钩子里对高度的处理,用户在设置页面绘图时也能完美运行。
保存到图库
最后一个功能:保存到图库!在toolbar上插入一个title为“保存到图库”的
UIBarButtonItem,还是可以先插入一个
FlexibleSpace的
UIBarButtonItem,然后把action连接到ViewController的
saveToAlbumy方法上:
<code class="language-swift hljs css has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-at_rule" style="box-sizing: border-box;">@<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">IBAction</span> func <span class="hljs-function" style="box-sizing: border-box; color: rgb(0, 102, 102);">saveToAlbum()</span> </span>{ <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">UIImageWriteToSavedPhotosAlbum</span>(<span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">self</span><span class="hljs-class" style="box-sizing: border-box; color: rgb(155, 112, 63);">.board</span><span class="hljs-class" style="box-sizing: border-box; color: rgb(155, 112, 63);">.takeImage</span>(), <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">self</span>, "<span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">image</span><span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:didFinishSavingWithError</span><span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:contextInfo</span><span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:"</span>, <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">nil</span>) }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>
我为
Board添加一个新的公共方法:takeImage:
<code class="language-swift hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">func takeImage() -> UIImage { UIGraphicsBeginImageContext(self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.bounds</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.size</span>) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.backgroundColor</span>?<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setFill</span>() UIRectFill(self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.bounds</span>) self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.image</span>?<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.drawInRect</span>(self<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.bounds</span>) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>
然后是一个方法指针的回调:
<code class="language-swift hljs vbscript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">func image(image: UIImage, didFinishSavingWithError <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">error</span>: NSError?, contextInfo:UnsafePointer<Void>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">let</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">err</span> = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">error</span> { UIAlertView(title: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"错误"</span>, message: <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">err</span>.localizedDescription, delegate: nil, cancelButtonTitle: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"确定"</span>).show() } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { UIAlertView(title: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"提示"</span>, message: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"保存成功"</span>, delegate: nil, cancelButtonTitle: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"确定"</span>).show() } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
旅行到终点了~!
感谢一路的陪伴!
看了下,有些小长,文本+代码有2w3+,全部代码去除空行和空格有1w4+,直接贴代码会简单很多,但我始终觉得让代码完成功能并不是全部目的,代码背后隐藏的问题定义、设计、构建更有意义,毕竟软件开发完成“后”比完成“前”所花费的时间永远更多(除非是一个只有10行代码或者“一次性”的程序)。希望与大家多多交流。
最后吐槽下CSDN新的Markdown编辑器,代码样式丑且不能自定义,而且有些代码高亮都无法识别。不过感觉草稿箱比以前更方便,问题主要还是集中在样式上,希望以后能不断改进,会一如既往的支持。
GitHub地址
DrawingBoard
相关文章推荐
- Swift 全功能的绘图板开发
- Swift 全功能的绘图板开发
- Swift 全功能的绘图板开发
- iOS开发项目实战——Swift实现ScrollView滚动条功能
- iOS开发---Swift相册框架,实现相片多选、反选等功能
- iOS开发 - Swift使用GCD实现计时器功能
- IOS开发笔记(Swift):通过ShareSDK和TYAlertController实现分享功能
- IOS开发Swift3 手电筒功能的实现
- Swift 绘图板功能完善以及终极优化
- IOS开发笔记(Swift):利用开源类库实现检测更新功能
- Ios swift 开发 使用ShardSDK 增加Facebook Twitter Instagram 分享功能
- iOS开发 - Swift实现清除缓存功能
- Swift / Objective_C / Xcode实际开发中可能遇到的小功能小技巧总结<持续添加更新...>
- Swift 绘图板功能完善以及终极优化
- IOS开发Swift使用NSURLSessionUploadTask实现后台上传功能
- iOS开发中Swift 指纹验证功能模块实例代码
- iOS开发项目实战——Swift实现ScrollView滚动栏功能
- iOS开发 - Swift使用GCD实现计时器功能
- 用BCB TClientSocket控件开发有身份认证功能的Email程序
- .net 开发的长内容自动分页功能(VB)