在 Swift 中优化屏幕反馈绘制立方贝塞尔曲线
Optimising on screen feedback drawing cubic bezier curved lines in Swift
当用户在屏幕上移动手指时,下面的代码会绘制曲线。三次贝塞尔曲线的绘制方法是addCurveToPoint
。然而,此方法需要完整的 1.. 2.. 3.. 4.. 触摸点才能在屏幕上绘制曲线。此方法会导致屏幕上出现非常短但明显的滞后反馈,因为在收集新触摸点时没有绘制任何内容。
使用代码example/s,可以在下面的代码中引入新的code/edits,例如在收集触摸点1.. 2.. 3..时画一条临时线,用一旦绘制了适当的曲线,临时线就会被移除,以便立即开始绘制印象?
或者,还有哪些其他技术可用并可用于为用户提供即时反馈,即使在正确绘制触摸点之前仍在收集触摸点,印象绘图已在屏幕上开始?
Note, the solution must be suitable for iOS7, iOS8 and iOS9 (i.e.
Advanced Touch Handling in iOS9 won't be suitable).
// Swift 2 code below tested using Xcode 7.0.1.
class drawView: UIView {
var path:UIBezierPath?
var incrementalImage:UIImage?
var points = [CGPoint?](count: 5, repeatedValue: nil)
var counter:Int?
var infoView:UIView = UIView()
var strokeColor:UIColor?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.multipleTouchEnabled = false
self.backgroundColor = UIColor.whiteColor()
path = UIBezierPath()
path?.lineWidth = 20.0
strokeColor = UIColor.darkGrayColor()
path?.lineCapStyle = CGLineCap.Round
}
override init(frame: CGRect) {
super.init(frame: frame)
self.multipleTouchEnabled = false
path = UIBezierPath()
path?.lineWidth = 20.0
}
override func drawRect(rect: CGRect) {
incrementalImage?.drawInRect(rect)
strokeColor?.setStroke()
path?.stroke()
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
counter = 0
let touch: AnyObject? = touches.first
points[0] = touch!.locationInView(self)
infoView.removeFromSuperview()
}
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 == 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()
}
}
当第一个点可用时,如何绘制低阶贝塞尔曲线?
2个点定义一条线性贝塞尔曲线(即一条线段),
3 个点定义二次贝塞尔曲线。
此外,你可以想到橡皮筋,即在最后一个点还在移动的时候重新绘制曲线(前一个点保持不动),直到你修复它并开始移动另一个。
当用户在屏幕上移动手指时,下面的代码会绘制曲线。三次贝塞尔曲线的绘制方法是addCurveToPoint
。然而,此方法需要完整的 1.. 2.. 3.. 4.. 触摸点才能在屏幕上绘制曲线。此方法会导致屏幕上出现非常短但明显的滞后反馈,因为在收集新触摸点时没有绘制任何内容。
使用代码example/s,可以在下面的代码中引入新的code/edits,例如在收集触摸点1.. 2.. 3..时画一条临时线,用一旦绘制了适当的曲线,临时线就会被移除,以便立即开始绘制印象?
或者,还有哪些其他技术可用并可用于为用户提供即时反馈,即使在正确绘制触摸点之前仍在收集触摸点,印象绘图已在屏幕上开始?
Note, the solution must be suitable for iOS7, iOS8 and iOS9 (i.e. Advanced Touch Handling in iOS9 won't be suitable).
// Swift 2 code below tested using Xcode 7.0.1.
class drawView: UIView {
var path:UIBezierPath?
var incrementalImage:UIImage?
var points = [CGPoint?](count: 5, repeatedValue: nil)
var counter:Int?
var infoView:UIView = UIView()
var strokeColor:UIColor?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.multipleTouchEnabled = false
self.backgroundColor = UIColor.whiteColor()
path = UIBezierPath()
path?.lineWidth = 20.0
strokeColor = UIColor.darkGrayColor()
path?.lineCapStyle = CGLineCap.Round
}
override init(frame: CGRect) {
super.init(frame: frame)
self.multipleTouchEnabled = false
path = UIBezierPath()
path?.lineWidth = 20.0
}
override func drawRect(rect: CGRect) {
incrementalImage?.drawInRect(rect)
strokeColor?.setStroke()
path?.stroke()
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
counter = 0
let touch: AnyObject? = touches.first
points[0] = touch!.locationInView(self)
infoView.removeFromSuperview()
}
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 == 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()
}
}
当第一个点可用时,如何绘制低阶贝塞尔曲线?
2个点定义一条线性贝塞尔曲线(即一条线段),
3 个点定义二次贝塞尔曲线。
此外,你可以想到橡皮筋,即在最后一个点还在移动的时候重新绘制曲线(前一个点保持不动),直到你修复它并开始移动另一个。