继我最近关于
3D Touch
和
触摸合并的
帖子之后,将两者结合在一个简单的绘图应用程序中似乎是显而易见的下一步。这也让我有机会修改 iOS 9 中新引入的
CIImageAccumulator
。
我的小型演示应用程序 ForceSketch 允许用户在他们的 iPhone 6 屏幕上绘图。线条粗细和线条颜色都与触摸压力相关联。就像我的 ChromaTouch 演示一样,压力控制色调,所以最轻的触摸是红色,在最大压力的三分之一时变成绿色,在三分之二时变成蓝色,在最大压力时变回红色。
一旦用户抬起手指,两个 Core Image 过滤器 CIColorControls 和 CIGaussianBlur 就会启动并使绘图淡出。
ForceSketch 的绘图机制
绘图代码都是从我的
视图控制器的
touchesMoved
方法调用的。在这里,我根据合并的触摸创建了一个
UIImage
实例,并将该图像合成到现有图像累加器上。在生产应用程序中,我可能会在后台线程中执行图像过滤以提高用户界面的性能,但是对于这个演示,我认为这种方法是可行的。
开头的
guard
语句确保我对最重要的项目有非可选常量:
guard let touch = touches.first,
event = event,
coalescedTouches = event.coalescedTouchesForTouch(touch) else
{
return
}
下一步是准备创建图像对象。为此,我需要开始图像上下文并创建对当前上下文的引用:
guard let touch = touches.first,
event = event,
coalescedTouches = event.coalescedTouchesForTouch(touch) else
{
return
}
为确保获得用户手势的最大保真度,我遍历合并的触摸 - 这为我提供了在调用 touchesMoved() 之间可能发生的所有中间触摸。
guard let touch = touches.first,
event = event,
coalescedTouches = event.coalescedTouchesForTouch(touch) else
{
return
}
使用每次触摸的
force
属性,我为线段颜色和粗细创建常量。为了确保使用非 3D Touch 设备的用户仍然使用该应用程序,我检查了
forceTouchCapability
并为这些用户提供了固定的权重和颜色:
guard let touch = touches.first,
event = event,
coalescedTouches = event.coalescedTouchesForTouch(touch) else
{
return
}
使用这些常量,我可以在图形上下文中设置线宽和描边颜色:
guard let touch = touches.first,
event = event,
coalescedTouches = event.coalescedTouchesForTouch(touch) else
{
return
}
...我现在准备好为这个合并的触摸定义我的线段的开始和结束:
guard let touch = touches.first,
event = event,
coalescedTouches = event.coalescedTouchesForTouch(touch) else
{
return
}
合并触摸循环中的最后一步是描边路径并更新
previousTouchLocation
:
guard let touch = touches.first,
event = event,
coalescedTouches = event.coalescedTouchesForTouch(touch) else
{
return
}
一旦所有的笔画都被添加到图形上下文中,只需一行代码就可以创建一个
UIImage
实例,然后结束上下文:
guard let touch = touches.first,
event = event,
coalescedTouches = event.coalescedTouchesForTouch(touch) else
{
return
}
显示绘制的线条
为了显示
drawnImage
中保存的新绘制的线条,我使用了一个
CISourceOverCompositing
过滤器,其中
drawnImage
作为前景图像,图像累加器的当前图像作为背景:
guard let touch = touches.first,
event = event,
coalescedTouches = event.coalescedTouchesForTouch(touch) else
{
return
}
然后通过合成器获取源的输出,将其传回累加器并使用累加器的图像填充我的
UIImageView
:
guard let touch = touches.first,
event = event,
coalescedTouches = event.coalescedTouchesForTouch(touch) else
{
return
}
模糊淡出
一旦用户抬起手指,我就会对绘制的图像进行“模糊淡出”。此效果使用两个定义为常量的 Core Image 过滤器:
guard let touch = touches.first,
event = event,
coalescedTouches = event.coalescedTouchesForTouch(touch) else
{
return
}
效果的第一部分是使用
CADisplayLink
,它将在每次屏幕刷新时调用
step()
:
guard let touch = touches.first,
event = event,
coalescedTouches = event.coalescedTouchesForTouch(touch) else
{
return
}
我依靠
previousTouchLocation
为 nil 来推断用户已完成触摸。如果是这种情况,我只需将累加器的当前图像传递到 HSB/颜色控制滤镜,将该滤镜的输出传递到高斯模糊,最后将模糊的输出传回累加器:
guard let touch = touches.first,
event = event,
coalescedTouches = event.coalescedTouchesForTouch(touch) else
{
return
}
源代码
一如既往,这个项目的源代码可以在 我的 GitHub 存储库 中找到。享受!