【发布时间】:2016-01-28 17:14:59
【问题描述】:
下面的代码通过覆盖触摸来绘制线条,但是在连续不间断的绘制期间开始出现滞后。手指在屏幕上移动的时间越长,这种滞后就会越积越多。结果是实际设备上的 CPU 几乎达到最大值(CPU 98%+),并且绘制的时间越长,生成的图像就越不稳定。
此外,当绘制速度特别快时,尤其是在圆圈中,path 和 temporaryPath(或 localPath)之间绘制的路径存在差异。尽管它们是在不同时间绘制的,但它们似乎同时出现在屏幕上,这在视觉上分散了两条快速绘制的路径。在下面的一张图片中,内部路径 (path) 似乎与外部路径 (temporaryPath) 相距一段距离。
1 - 如何消除一段时间连续绘制的滞后延迟?
2 - 如何消除绘制路径的差异?
3 - 如何更改 path 和 temporaryPath 的 alpha/opacity?
class swiftView: UIView {
var strokeColor = UIColor.blueColor()
var lineWidth: CGFloat = 5
var snapshotImage: UIImage?
private var path: UIBezierPath?
private var temporaryPath: UIBezierPath?
private var points = [CGPoint]()
var counterPoints:Int?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func drawRect(rect: CGRect) {
autoreleasepool {
snapshotImage?.drawInRect(rect)
strokeColor.setStroke()
path?.stroke()
temporaryPath?.stroke()
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
points = [touch!.locationInView(self)]
counterPoints = 0
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let point = touch!.locationInView(self)
points.append(point)
let pointCount = points.count
counterPoints = counterPoints! + 1
if pointCount == 2 {
temporaryPath = createPathStartingAtPoint(points[0])
temporaryPath?.addLineToPoint(points[1])
setNeedsDisplay()
} else if pointCount == 3 {
temporaryPath = createPathStartingAtPoint(points[0])
temporaryPath?.addQuadCurveToPoint(points[2], controlPoint: points[1])
setNeedsDisplay()
} else if pointCount == 4 {
temporaryPath = createPathStartingAtPoint(points[0])
temporaryPath?.addCurveToPoint(points[3], controlPoint1: points[1], controlPoint2: points[2])
// setNeedsDisplay()
if counterPoints! < 50 {
self.setNeedsDisplay()
} else {
temporaryPath = nil
self.constructIncrementalImage()
path = nil
self.setNeedsDisplay()
counterPoints = 0
}
} else if pointCount == 5 {
points[3] = CGPointMake((points[2].x + points[4].x)/2.0, (points[2].y + points[4].y)/2.0)
// create a quad bezier up to point 4, too
if points[4] != points[3] {
let length = hypot(points[4].x - points[3].x, points[4].y - points[3].y) / 2.0
let angle = atan2(points[3].y - points[2].y, points[4].x - points[3].x)
let controlPoint = CGPoint(x: points[3].x + cos(angle) * length, y: points[3].y + sin(angle) * length)
temporaryPath = createPathStartingAtPoint(points[3])
temporaryPath?.addQuadCurveToPoint(points[4], controlPoint: controlPoint)
} else {
temporaryPath = nil
}
if path == nil {
path = createPathStartingAtPoint(points[0])
}
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?) {
self.constructIncrementalImage()
path = nil
self.setNeedsDisplay()
counterPoints = 0
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
self.touchesEnded(touches!, withEvent: event)
}
private func createPathStartingAtPoint(point: CGPoint) -> UIBezierPath {
let localPath = UIBezierPath()
localPath.moveToPoint(point)
localPath.lineWidth = lineWidth
localPath.lineCapStyle = .Round
localPath.lineJoinStyle = .Round
return localPath
}
private func constructIncrementalImage() {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0.0)
strokeColor.setStroke()
snapshotImage?.drawAtPoint(CGPointZero)
path?.stroke()
temporaryPath?.stroke()
snapshotImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
【问题讨论】:
-
你说“我已经尝试在大约 50 个连续绘图点之后在 pointCount == 4 时缓存绘图”。好吧,也许您应该向我们展示该代码,因为这正是解决此问题的方法。但也许 50 太少了(因为当您谈论手势时,触摸会迅速增加,尤其是在使用合并触摸的情况下)。但拍摄快照是典型的解决方案(意识到快照过程本身很慢,因此您需要平衡快照的频率和路径的长度)。
-
@Rob 是的,一些更新的代码会很有帮助。我已经更新了,抱歉。我还更新了问题。代码中添加了一个变量
counterPoints。我还将autoreleasepool添加到drawRect以帮助避免课程崩溃。不确定这是否有用或不必要,但我注意到它可以帮助避免过去的 CPU 崩溃。因为我在 iOS7 和 iOS9 上试验,所以没有使用合并的触摸。谢谢。
标签: ios swift drawing uibezierpath