use*_*509 3 drawing ios uibezierpath swift
下面的代码通过覆盖触摸来绘制线条,但是在绘制时仍然存在伪像,如下图所示。
当在屏幕上进行锯齿形绘制时改变方向时,有时线会变成平坦的直角,而不是保持圆形。当在小圆圈上现场绘制时,也会出现伪影,当手指离开屏幕时,绘制点会闪烁半个圆圈,有时会留下半个圆圈和部分圆圈残留物。
伪影是断断续续的,不是完全一致或可预测的,这使得很难在代码中找到问题。它同时存在于模拟器和iOS7-iOS9的设备中。
包含两个绘制点和线的视频屏幕截图以及Xcode项目的zip文件以名为Archive.zip(23MB)https://www.dropbox.com/s/hm39rdiuk0mf578/Archive.zip?dl的文件上传到DropBox。= 0
问题:
1-在代码中,造成此点/半圆伪像的原因是什么?如何纠正?
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
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()
}
}
Run Code Online (Sandbox Code Playgroud)
这似乎是一个令人着迷的错误,addQuadCurveToPoint并且addCurveToPoint如果控制点与两个端点在同一行上,则它不适合lineJoinStyle。因此,您可以对此进行测试(通过查看atan2各个要点,并确保不相同),如果是这样,请addLineToPoint改为执行以下操作:
我发现此修改后的代码删除了这些工件:
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])
}
addCubicCurveToPath(path)
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])
addQuadCurveToPath(temporaryPath)
} else if pointCount == 4 {
temporaryPath = createPathStartingAtPoint(points[0])
addCubicCurveToPath(temporaryPath)
}
}
/// Add cubic curve to path
///
/// Because of bug with bezier curves that fold back on themselves do no honor `lineJoinStyle`,
/// check to see if this occurs, and if so, just add lines rather than cubic bezier path.
private func addCubicCurveToPath(somePath: UIBezierPath?) {
let m01 = atan2(points[0].x - points[1].x, points[0].y - points[1].y)
let m23 = atan2(points[2].x - points[3].x, points[2].y - points[3].y)
let m03 = atan2(points[0].x - points[3].x, points[0].y - points[3].y)
if m01 == m03 || m23 == m03 || points[0] == points[3] {
somePath?.addLineToPoint(points[1])
somePath?.addLineToPoint(points[2])
somePath?.addLineToPoint(points[3])
} else {
somePath?.addCurveToPoint(points[3], controlPoint1: points[1], controlPoint2: points[2])
}
}
/// Add quadratic curve to path
///
/// Because of bug with bezier curves that fold back on themselves do no honor `lineJoinStyle`,
/// check to see if this occurs, and if so, just add lines rather than quadratic bezier path.
private func addQuadCurveToPath(somePath: UIBezierPath?) {
let m01 = atan2(points[0].x - points[1].x, points[0].y - points[1].y)
let m12 = atan2(points[1].x - points[2].x, points[1].y - points[2].y)
let m02 = atan2(points[0].x - points[2].x, points[0].y - points[2].y)
if m01 == m02 || m12 == m02 || points[0] == points[2] {
somePath?.addLineToPoint(points[1])
somePath?.addLineToPoint(points[2])
} else {
somePath?.addQuadCurveToPoint(points[2], controlPoint: points[1])
}
}
Run Code Online (Sandbox Code Playgroud)
同样,这可能过于谨慎,但要确保两个连续的点在guard声明中永远不会相同是谨慎的:
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let point = touch!.locationInView(self)
guard point != points.last else { return }
points.append(point)
totalPointCount = totalPointCount + 1
updatePaths()
if totalPointCount > 50 {
constructIncrementalImage(includeTemporaryPath: false)
path = nil
totalPointCount = 0
}
setNeedsDisplay()
}
Run Code Online (Sandbox Code Playgroud)
如果您发现其他存在问题的情况,则可以重复我刚才所做的调试练习。即,运行代码,直到出现问题为止,但立即停止并查看points数组日志以查看是什么原因导致了问题,然后创建一个init?(coder:)始终100%始终再现问题的代码,例如:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
points.append(CGPoint(x: 239.33332824707, y: 419.0))
points.append(CGPoint(x: 239.33332824707, y: 420.0))
points.append(CGPoint(x: 239.33332824707, y: 419.3))
updatePaths()
}
Run Code Online (Sandbox Code Playgroud)
然后,由于始终存在可复制的问题,因此调试很容易。因此,诊断出问题之后,我进行了修改,updatePaths直到问题解决为止。然后,我注释掉init?并重复了整个练习。
| 归档时间: |
|
| 查看次数: |
864 次 |
| 最近记录: |