为什么画了很长时间后我的画会卡顿?
Why does my drawing lag after drawing for a long period of time?
我正在创建一个绘图应用程序。一开始我的画很流畅。当我长时间画一堆圆圈时,我的画开始变得急躁。或许是因为一个数组不能处理太多的点?
DV.swift:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
lastPoint = touches.first!.locationInView(self)
self.setNeedsDisplay()
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
var newPoint = touches.first!.locationInView(self)
lines.append(Line(start: lastPoint, end: newPoint))
lastPoint = newPoint
self.setNeedsDisplay()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
var veryFirstPoint = touches.first!.locationInView(self)
lines.append(Line(start: lastPoint, end:veryFirstPoint))
self.setNeedsDisplay()
}
override func drawRect(rect: CGRect) {
var context = UIGraphicsGetCurrentContext()
CGContextBeginPath(context)
for line in lines {
CGContextMoveToPoint(context,line.start.x , line.start.y)
CGContextAddLineToPoint(context, line.end.x, line.end.y)
}
CGContextSetRGBFillColor(context, 0, 0, 0, 1)
CGContextSetLineWidth(context, 5)
CGContextStrokePath(context)
}
在我的 iPad mini 4 上测试的示例:
左边是画了一堆环后的锯齿状数字。右边是我画的前几个数字,很流畅
你是对的。每次添加新的 "line" 时,您都会 CPU 重绘许多路径,即在每次触摸之后。您拥有的线路越多,处理器密集程度就越高。一种解决方案是仅重绘视图的 "dirty" 部分。您可以使用 setNeedsDisplayInRect(rect:CGRect)
而不是 setNeedsDisplay()
来做到这一点。例如,您可以添加扩展名:
extension CGRect{
static func rectWithTwoPoints(p1:CGPoint,p2:CGPoint) -> CGRect
{
return CGRectMake(min(p1.x, p2.x),min(p1.y, p2.y),fabs(p1.x - p2.x),fabs(p1.y - p2.y));
}
}
这将给我一个包含任意两点的矩形。现在,在您的 touchesMoved:
和 touchesEnded:
中,我们可以这样调用 setNeedsDisplayInRect:
:
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let newPoint = touches.first!.locationInView(self)
lines.append(Line(start: lastPoint, end: newPoint))
lastPoint = newPoint
self.setNeedsDisplayInRect(CGRectInset(CGRect.rectWithTwoPoints((lines.last?.start)!, p2: (lines.last?.end)!),-10.0,-10.0)) //would be better to not force unwrap and use magic numbers, but you get the idea
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
let veryFirstPoint = touches.first!.locationInView(self)
lines.append(Line(start: lastPoint, end:veryFirstPoint))
self.setNeedsDisplayInRect(CGRectInset(CGRect.rectWithTwoPoints((lines.last?.start)!, p2: (lines.last?.end)!),-10.0,-10.0))
}
使用 CGRectInset
稍微扩展我们的矩形,因为我们有一个路径宽度,如果我们只重绘 rectWithTwoPoints 返回的矩形会考虑到。
我正在创建一个绘图应用程序。一开始我的画很流畅。当我长时间画一堆圆圈时,我的画开始变得急躁。或许是因为一个数组不能处理太多的点?
DV.swift:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
lastPoint = touches.first!.locationInView(self)
self.setNeedsDisplay()
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
var newPoint = touches.first!.locationInView(self)
lines.append(Line(start: lastPoint, end: newPoint))
lastPoint = newPoint
self.setNeedsDisplay()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
var veryFirstPoint = touches.first!.locationInView(self)
lines.append(Line(start: lastPoint, end:veryFirstPoint))
self.setNeedsDisplay()
}
override func drawRect(rect: CGRect) {
var context = UIGraphicsGetCurrentContext()
CGContextBeginPath(context)
for line in lines {
CGContextMoveToPoint(context,line.start.x , line.start.y)
CGContextAddLineToPoint(context, line.end.x, line.end.y)
}
CGContextSetRGBFillColor(context, 0, 0, 0, 1)
CGContextSetLineWidth(context, 5)
CGContextStrokePath(context)
}
在我的 iPad mini 4 上测试的示例: 左边是画了一堆环后的锯齿状数字。右边是我画的前几个数字,很流畅
你是对的。每次添加新的 "line" 时,您都会 CPU 重绘许多路径,即在每次触摸之后。您拥有的线路越多,处理器密集程度就越高。一种解决方案是仅重绘视图的 "dirty" 部分。您可以使用 setNeedsDisplayInRect(rect:CGRect)
而不是 setNeedsDisplay()
来做到这一点。例如,您可以添加扩展名:
extension CGRect{
static func rectWithTwoPoints(p1:CGPoint,p2:CGPoint) -> CGRect
{
return CGRectMake(min(p1.x, p2.x),min(p1.y, p2.y),fabs(p1.x - p2.x),fabs(p1.y - p2.y));
}
}
这将给我一个包含任意两点的矩形。现在,在您的 touchesMoved:
和 touchesEnded:
中,我们可以这样调用 setNeedsDisplayInRect:
:
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let newPoint = touches.first!.locationInView(self)
lines.append(Line(start: lastPoint, end: newPoint))
lastPoint = newPoint
self.setNeedsDisplayInRect(CGRectInset(CGRect.rectWithTwoPoints((lines.last?.start)!, p2: (lines.last?.end)!),-10.0,-10.0)) //would be better to not force unwrap and use magic numbers, but you get the idea
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
let veryFirstPoint = touches.first!.locationInView(self)
lines.append(Line(start: lastPoint, end:veryFirstPoint))
self.setNeedsDisplayInRect(CGRectInset(CGRect.rectWithTwoPoints((lines.last?.start)!, p2: (lines.last?.end)!),-10.0,-10.0))
}
使用 CGRectInset
稍微扩展我们的矩形,因为我们有一个路径宽度,如果我们只重绘 rectWithTwoPoints 返回的矩形会考虑到。