你问:
- 如何消除连续绘制一段时间的滞后现象?
正如您正确推测的那样,是的,执行快照并重置路径可以通过限制路径的长度来解决此问题。
我知道您已经意识到这一点,但为了其他读者的利益,在 iOS 9 中您也可以使用预测触摸。在这个特定的算法中(其中(a)您只是添加到路径,但是(b)每四个点根据下一个点进行调整,以确保两条三次贝塞尔曲线连接处没有不连续性)有点棘手,但可以做到。
- 如何消除所绘制路径的差异?
这是因为快照包含临时路径而导致的。但该临时路径的全部目的是,随着更多点的进入,它将被丢弃。因此,您不应将其包含在手势中创建的快照中。
因此,我建议向快照函数添加一个参数,指示是否temporaryPath
应包含或不包含。当调用它的中间手势时,您需要指定includeTemporaryPath
as false
,但是当在手势结束时调用它时,includeTemporaryPath
将会true
.
例如:
class SmoothCurvedLinesView: UIView {
var strokeColor = UIColor.blueColor()
var lineWidth: CGFloat = 20
var snapshotImage: UIImage?
private var path: UIBezierPath?
private var temporaryPath: UIBezierPath?
private var points = [CGPoint]()
private var totalPointCount = 0
override func drawRect(rect: CGRect) {
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)]
totalPointCount = totalPointCount + 1
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let point = touch!.locationInView(self)
points.append(point)
totalPointCount = totalPointCount + 1
updatePaths()
if totalPointCount > 50 {
constructIncrementalImage(includeTemporaryPath: false)
path = nil
totalPointCount = 0
}
setNeedsDisplay()
}
private func updatePaths() {
// update main path
while points.count > 4 {
points[3] = CGPointMake((points[2].x + points[4].x)/2.0, (points[2].y + points[4].y)/2.0)
if path == nil {
path = createPathStartingAtPoint(points[0])
}
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 {
temporaryPath = createPathStartingAtPoint(points[0])
temporaryPath?.addLineToPoint(points[1])
} else if pointCount == 3 {
temporaryPath = createPathStartingAtPoint(points[0])
temporaryPath?.addQuadCurveToPoint(points[2], controlPoint: points[1])
} else if pointCount == 4 {
temporaryPath = createPathStartingAtPoint(points[0])
temporaryPath?.addCurveToPoint(points[3], controlPoint1: points[1], controlPoint2: points[2])
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
constructIncrementalImage()
path = nil
temporaryPath = nil
setNeedsDisplay()
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
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(includeTemporaryPath includeTemporaryPath: Bool = true) {
UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.0)
strokeColor.setStroke()
snapshotImage?.drawAtPoint(CGPointZero)
path?.stroke()
if (includeTemporaryPath) { temporaryPath?.stroke() }
snapshotImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
顺便说一句,虽然我是提供路径生成代码的人,但我意识到它可以稍微简化一下。我也修复了一个错误。参见上面的代码。
然后你问:
- 如何更改路径和临时路径的 alpha/不透明度?
您只需调整调用的颜色即可setStroke
具有适当的阿尔法。例如,如果您希望临时路径位于alpha
对于主路径,您可以执行以下操作:
override func drawRect(rect: CGRect) {
snapshotImage?.drawInRect(rect)
strokeColor.setStroke()
path?.stroke()
strokeColor.colorWithAlphaComponent(0.5).setStroke()
temporaryPath?.stroke()
}