Removing lagging latency during continuous period of drawing UIBezierPath in Swift
下面的代码通过覆盖触摸来绘制线条,但是在连续不间断的绘制期间开始出现滞后。手指在屏幕上移动的时间越长,这种滞后就会越积越多。结果是实际设备上的 CPU 几乎达到最大值(CPU 98% ),并且绘制的时间越长,生成的图像就越不稳定。
此外,当画得特别快时,尤其是在圆圈中,在 path 和 temporaryPath(或 localPath)之间绘制的路径存在差异。尽管它们是在不同时间绘制的,但它们似乎同时出现在屏幕上,这在视觉上分散了两条快速绘制的路径。在下面的图像之一中,内部路径 (path) 似乎与外部路径 (temporaryPath) 相距一段距离。
1 – 如何消除连续绘制一段时间的滞后延迟?
2 – 如何消除绘制路径的差异?
3 – 如何更改 path 和 temporaryPath 的 alpha/opacity?
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
class swiftView: UIView {
var strokeColor = UIColor.blueColor() private var path: UIBezierPath? var counterPoints:Int? required init?(coder aDecoder: NSCoder) { override func drawRect(rect: CGRect) { snapshotImage?.drawInRect(rect) strokeColor.setStroke() path?.stroke() } override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { counterPoints = 0 override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) { points.append(point) counterPoints = counterPoints! + 1 if pointCount == 2 { if counterPoints! < 50 { } else if pointCount == 5 { // create a quad bezier up to point 4, too if points[4] != points[3] { temporaryPath = createPathStartingAtPoint(points[3]) if path == nil { path?.addCurveToPoint(points[3], controlPoint1: points[1], controlPoint2: points[2]) self.setNeedsDisplay() points = [points[3], points[4]] override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { counterPoints = 0 override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) { private func createPathStartingAtPoint(point: CGPoint) -> UIBezierPath { localPath.moveToPoint(point) localPath.lineWidth = lineWidth return localPath private func constructIncrementalImage() { } |
- 你说”我已经尝试在大约 50 个连续绘图点后 pointCount == 4 时缓存绘图”。好吧,也许您应该向我们展示该代码,因为这正是解决此问题的方法。但也许 50 太少了(因为当您谈论手势时,触摸会迅速增加,尤其是在使用合并触摸的情况下)。但是拍摄快照是典型的解决方案(意识到快照过程本身很慢,因此您需要平衡快照的频率和路径的长度)。
- @Rob是的,一些更新的代码会有所帮助。我已经更新了它,对此感到抱歉。我还更新了问题。在代码中,添加了一个变量 counterPoints。我还添加了 autoreleasepool 到 drawRect 以帮助避免类崩溃。不确定这是否有用或不必要,但我注意到它有时可以帮助避免过去的 CPU 崩溃。 Coalesced touches 还没有被用作 Ia€?m 在 iOS7 和 iOS9 上的实验。谢谢你。
你问过:
How can the lagging latency over a period of continuous drawing be eliminated?
正如您正确推测的那样,是的,创建快照并重置路径可以通过限制路径的长度来解决此问题。
我知道您已经意识到这一点,但为了其他读者的利益,在 iOS 9 中您也可以使用预测性触控。在这个特定的算法中(其中(a)您只是添加到路径,但(b)每四个点根据下一个点进行调整,以确保两条三次贝塞尔曲线连接处没有不连续性)有点棘手,但可以做到。
How can the discrepancy in the paths drawn be eliminated?
这是因为快照包含临时路径。但是该临时路径的全部目的是随着更多点的进入,它将被丢弃。因此,您不应将其包含在您创建的中间手势快照中。
所以,我建议在快照函数中添加一个参数,指示是否应包含 temporaryPath。当在手势中调用它时,您将指定 includeTemporaryPath 为 false,但在手势结束时调用它时,includeTemporaryPath 将是 true.
例如:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
class SmoothCurvedLinesView: UIView {
var strokeColor = UIColor.blueColor() var lineWidth: CGFloat = 20 var snapshotImage: UIImage? private var path: UIBezierPath? override func drawRect(rect: CGRect) { strokeColor.setStroke() path?.stroke() override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) { points.append(point) updatePaths() if totalPointCount > 50 { setNeedsDisplay() private func updatePaths() { while points.count > 4 { if path == nil { path?.addCurveToPoint(points[3], controlPoint1: points[1], controlPoint2: points[2]) points.removeFirst(3) // build temporary path up to last touch point let pointCount = points.count if pointCount == 2 { override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) { private func createPathStartingAtPoint(point: CGPoint) -> UIBezierPath { localPath.moveToPoint(point) localPath.lineWidth = lineWidth return localPath private func constructIncrementalImage(includeTemporaryPath includeTemporaryPath: Bool = true) { |
顺便说一句,虽然我是提供路径生成代码的人,但我意识到它可以简化一点。我也修复了一个错误。见上面的代码。
然后你问:
How can the alpha/opacity of the path and temporaryPath be changed?
您可以使用适当的 alpha 调整调用 setStroke 时使用的颜色。例如,如果您希望临时路径位于主路径 alpha 的一半,您可以执行以下操作:
1
2 3 4 5 6 7 8 9 |
override func drawRect(rect: CGRect) {
snapshotImage?.drawInRect(rect) strokeColor.setStroke() strokeColor.colorWithAlphaComponent(0.5).setStroke() |
- 谢谢。我喜欢简化代码的想法——紧凑!但我注意到,自从更改后,有时绘图末尾会出现一条双线,图片:i.imgur.com/vU96UT5.png 为了尝试追踪问题,我设置了 lineWidth: CGFloat = 1 并添加了print(points.count) 到 touchesEnded 的开头。当 points.count = 2 双线出现但我无法弄清楚为什么要比较以前的代码时,结果是这样的。 (它不会发生在 3 和 4 上。)关于它可能是什么的任何想法?
- 我在上面的代码中注意到了一个伪影。我在以下位置发布的详细信息:stackoverflow.com/questions/35608766
来源:https://www.codenong.com/35067811/