下面的代碼通過覆蓋觸摸來繪製線條,但是滯後開始在連續不停止繪製的一段時間內發生。手指在屏幕上移動的時間越長,這種滯後越積累並越糟。結果是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