下面的代码通过覆盖触摸来绘制平滑的曲线,但是存在明显的滞后或延迟。该代码每隔4个接触点使用addCurveToPoint并调用setNeedsDisplay一次,这会导致跳动的外观,因为图形无法跟上手指的移动。为了消除延迟或察觉到的延迟,可以用addQuadCurveToPoint和临时填充触摸点1、2、3(直至触摸点4)addLineToPoint。
addCurveToPoint
setNeedsDisplay
addQuadCurveToPoint
addLineToPoint
在代码中,如何在显示最终弯曲线之前通过使用临时线和QuadCurved线来实际消除滞后现象,从而在代码中实现呢?
如果将下面的类附加到一个类UIView(例如viewOne或self)上,如何UIView在该类之后将图形副本复制到该类之外的另一个类(例如viewTwo)上touchesEnded?
UIView
self
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. }
points[1]
points[2]
points[3]
正如您所说,请确保将其添加到单独的路径。因此,在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() } }
您甚至可以将此与iOS9预测性触控结合使用如我在其他答案中所述,这可以进一步减少延迟。
incrementalImage
snapshotImage