下面的代码通过覆盖触摸来绘制线条,但是滞后开始在连续不停止绘制的一段时间内发生。手指在屏幕上移动的时间越长,这种滞后越积累并越糟。结果是CPU在实际设备(CPU 98%+)上几乎达到最大值,并且随着绘图的持续时间越长,结果图像看起来不稳定。在Swift中连续绘制UIBezierPath期间删除滞后延迟
另外,特别是在圈出特别快时,在path
和temporaryPath
(或localPath
)之间绘制的路径存在差异。尽管它们在不同的时间被绘制出来,但它们似乎同时出现在屏幕上,看起来两条路径很快就会分散注意力。内部路径(path
)似乎与外部路径(temporaryPath
)之间的距离远远高于下图之一中以红色突出显示的距离。
1 - 如何消除一段连续绘制的滞后延迟?
2 - 如何消除路径中的差异?
3 - 如何更改path
和temporaryPath
的alpha /不透明度?
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()
}
}
你说“我已经试过缓存绘图时pointCount == 4后约50个连续绘图点“。那么,也许你应该向我们展示那些代码,因为这正是解决这个问题的方法。但是也许50个人太少(因为当你谈论手势时,触动很快就会架起来,尤其是在使用合并触摸时)。但拍摄快照是典型的解决方案(意识到快照过程本身很慢,所以您需要平衡快照频率与路径长度)。 – Rob
@Rob是的,一些更新的代码会有帮助。我已经更新了,对此表示遗憾。我也更新了问题。代码中添加了一个变量'counterPoints'。我还将'autoreleasepool'添加到'drawRect'以帮助避免类崩溃。不确定这是否有用或不必要,但我注意到它可以帮助有时避免CPU崩溃。我在iOS7以及iOS9上进行实验时,没有使用合并触摸。谢谢。 – user4806509