在Swift中去除绘制UIBezierPath平滑线的滞后延迟

下面的代码通过覆盖触摸绘制平滑的曲线,但是有明显的滞后或延迟。 该代码使用addCurveToPoint并在每触摸4个点后调用setNeedsDisplay ,由于graphics跟不上手指的移动,导致出现跳动的外观。 为了消除滞后或潜在的等待时间,可以使用addQuadCurveToPointaddLineToPoint临时填充触摸点1,2,3(触及点4)。

  1. 在代码中如何实际实现,通过在显示最终的Curved行之前使用临时的Line和QuadCurved行来消除感知的滞后?

  2. 如果下面的类被附加到一个UIView (例如viewOne或self ),那么在touchesEnded之后,如何将绘图的副本复制到另一个UIView (例如viewTwo) touchesEnded

      // ViewController.swift import UIKit class drawSmoothCurvedLinesWithLagging: UIView { let path=UIBezierPath() var incrementalImage:UIImage? var points = [CGPoint?](count: 5, repeatedValue: nil) var counter:Int? var strokeColor:UIColor? required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override func drawRect(rect: CGRect) { autoreleasepool { incrementalImage?.drawInRect(rect) strokeColor = UIColor.blueColor() strokeColor?.setStroke() path.lineWidth = 20 path.lineCapStyle = CGLineCap.Round path.stroke() } } override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { counter = 0 let touch: AnyObject? = touches.first points[0] = touch!.locationInView(self) } override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) { let touch: AnyObject? = touches.first let point = touch!.locationInView(self) counter = counter! + 1 points[counter!] = point if counter == 2{ //use path.addLineToPoint ? //use self.setNeedsDisplay() ? } if counter == 3{ //use path.addQuadCurveToPoint ? //use self.setNeedsDisplay() ? } if counter == 4{ points[3]! = CGPointMake((points[2]!.x + points[4]!.x)/2.0, (points[2]!.y + points[4]!.y)/2.0) path.moveToPoint(points[0]!) path.addCurveToPoint(points[3]!, controlPoint1: points[1]!, controlPoint2: points[2]!) self.setNeedsDisplay() points[0]! = points[3]! points[1]! = points[4]! counter = 1 } } override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { self.drawBitmap() self.setNeedsDisplay() path.removeAllPoints() counter = 0 } override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) { self.touchesEnded(touches!, withEvent: event) } func drawBitmap(){ UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 0.0) strokeColor?.setStroke() if((incrementalImage) == nil){ let rectPath:UIBezierPath = UIBezierPath(rect: self.bounds) UIColor.whiteColor().setFill() rectPath.fill() } incrementalImage?.drawAtPoint(CGPointZero) path.stroke() incrementalImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() } } class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } 

  1. 是的,每隔几个点添加一条曲线就会导致延迟。 所以,是的,你可以通过添加一条线points[1] ,添加一个四边形曲线points[2]并添加一个三次曲线points[3]来减less这种影响。

    正如你所说的,一定要把它添加到一个单独的path,虽然。 所以,在Swift 3/4:

     class SmoothCurvedLinesView: UIView { var strokeColor = UIColor.blue var lineWidth: CGFloat = 20 var snapshotImage: UIImage? private var path: UIBezierPath? private var temporaryPath: UIBezierPath? private var points = [CGPoint]() override func draw(_ rect: CGRect) { snapshotImage?.draw(in: rect) strokeColor.setStroke() path?.stroke() temporaryPath?.stroke() } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { points = [touch.location(in: self)] } } override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touch = touches.first else { return } let point = touch.location(in: self) points.append(point) updatePaths() setNeedsDisplay() } private func updatePaths() { // update main path while points.count > 4 { points[3] = CGPoint(x: (points[2].x + points[4].x)/2.0, y: (points[2].y + points[4].y)/2.0) if path == nil { path = createPathStarting(at: points[0]) } path?.addCurve(to: points[3], controlPoint1: points[1], controlPoint2: points[2]) points.removeFirst(3) temporaryPath = nil } // build temporary path up to last touch point if points.count == 2 { temporaryPath = createPathStarting(at: points[0]) temporaryPath?.addLine(to: points[1]) } else if points.count == 3 { temporaryPath = createPathStarting(at: points[0]) temporaryPath?.addQuadCurve(to: points[2], controlPoint: points[1]) } else if points.count == 4 { temporaryPath = createPathStarting(at: points[0]) temporaryPath?.addCurve(to: points[3], controlPoint1: points[1], controlPoint2: points[2]) } } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { finishPath() } override func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) { finishPath() } private func finishPath() { constructIncrementalImage() path = nil setNeedsDisplay() } private func createPathStarting(at point: CGPoint) -> UIBezierPath { let localPath = UIBezierPath() localPath.move(to: point) localPath.lineWidth = lineWidth localPath.lineCapStyle = .round localPath.lineJoinStyle = .round return localPath } private func constructIncrementalImage() { UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.0) strokeColor.setStroke() snapshotImage?.draw(at: .zero) path?.stroke() temporaryPath?.stroke() snapshotImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() } } 

    你甚至可以用iOS 9预测性的方法来结婚(就像我在其他答案中所描述的那样 ),这可以进一步减less延迟。

  2. 要获得这个结果的图像并在其他地方使用它,你可以抓取incrementalImage (我将其重命名为snapshotImage ,在上面),并将其放到另一个视图的图像视图中。

Swift 2翻译,请参阅此答案的以前的修订 。