绘制多条线时的 drawRect 性能
drawRect performance when drawing many lines
我正在尝试在自定义视图的 drawRect
方法中绘制程序生成的树。这对大约 20k 行来说非常灵活。超过这一点,绘图性能就会完全下降(即绘制树的时间将近 1000 毫秒)。
绘制树的绘制代码为:
func drawBranch( branch: Branch, context :CGContext ) {
CGContextMoveToPoint(context, (branch.originPoint().x), (branch.originPoint().y))
CGContextAddLineToPoint(context, (branch.endPoint().x), (branch.endPoint().y))
for b in branch.children {
drawBranch(b, context: context)
}
}
override func drawRect(rect: CGRect) {
print("\(NSDate()) drawRect")
// Setup graphics context
let ctx = UIGraphicsGetCurrentContext()
// clear context
CGContextClearRect(ctx, rect)
CGContextSetRGBFillColor(ctx, 0.0, 0.0, 0.0, 1.0)
CGContextFillRect(ctx, rect)
CGContextSaveGState(ctx);
CGContextTranslateCTM(ctx, 0.0, rect.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextSetShouldAntialias(ctx, true)
CGContextSetRGBStrokeColor(ctx, 0.3, 0.3, 0.3, 1)
if let tree = self.tree {
drawBranch(tree, context: ctx)
}
CGContextStrokePath(ctx)
CGContextRestoreGState(ctx);
}
是否有任何希望让它变得更快,或者我应该早就放弃并转向其他渲染 method/engine?
我通读了 this question here,这似乎暗示它永远不会起作用,但那是 3 年前的事了,我想知道从那时起是否有任何变化。
您可以改为将路径视为数据,即每当影响树的某些更改(例如添加分支)时,重新计算路径并重绘,这样您只需支付 1 秒的惩罚一次.
基本上,您需要重构 drawBranch
函数,而不是将 绘制到 上下文中,return 一个 CGPath
对象。然后可以将其保留在视图中并在 drawRect:
方法中重新绘制。
另一种选择是使用 CATiledLayer,但前提是您能够一次只绘制部分视图(例如,您可以将绘图拆分为 100x100 像素的图块)。这不一定会使速度更快,但可以避免绘制树中当前不可见的部分,并且只在需要时才绘制它们。
简而言之,尝试将确定树(模型)路径的逻辑与表示(将其绘制到CGContext
中)分开。生成树路径完全有可能是一项昂贵的操作,但至少通过将其与绘图分开,您可以避免阻塞主线程,并确保尽可能少地完成耗时的计算。
我正在尝试在自定义视图的 drawRect
方法中绘制程序生成的树。这对大约 20k 行来说非常灵活。超过这一点,绘图性能就会完全下降(即绘制树的时间将近 1000 毫秒)。
绘制树的绘制代码为:
func drawBranch( branch: Branch, context :CGContext ) {
CGContextMoveToPoint(context, (branch.originPoint().x), (branch.originPoint().y))
CGContextAddLineToPoint(context, (branch.endPoint().x), (branch.endPoint().y))
for b in branch.children {
drawBranch(b, context: context)
}
}
override func drawRect(rect: CGRect) {
print("\(NSDate()) drawRect")
// Setup graphics context
let ctx = UIGraphicsGetCurrentContext()
// clear context
CGContextClearRect(ctx, rect)
CGContextSetRGBFillColor(ctx, 0.0, 0.0, 0.0, 1.0)
CGContextFillRect(ctx, rect)
CGContextSaveGState(ctx);
CGContextTranslateCTM(ctx, 0.0, rect.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextSetShouldAntialias(ctx, true)
CGContextSetRGBStrokeColor(ctx, 0.3, 0.3, 0.3, 1)
if let tree = self.tree {
drawBranch(tree, context: ctx)
}
CGContextStrokePath(ctx)
CGContextRestoreGState(ctx);
}
是否有任何希望让它变得更快,或者我应该早就放弃并转向其他渲染 method/engine?
我通读了 this question here,这似乎暗示它永远不会起作用,但那是 3 年前的事了,我想知道从那时起是否有任何变化。
您可以改为将路径视为数据,即每当影响树的某些更改(例如添加分支)时,重新计算路径并重绘,这样您只需支付 1 秒的惩罚一次.
基本上,您需要重构 drawBranch
函数,而不是将 绘制到 上下文中,return 一个 CGPath
对象。然后可以将其保留在视图中并在 drawRect:
方法中重新绘制。
另一种选择是使用 CATiledLayer,但前提是您能够一次只绘制部分视图(例如,您可以将绘图拆分为 100x100 像素的图块)。这不一定会使速度更快,但可以避免绘制树中当前不可见的部分,并且只在需要时才绘制它们。
简而言之,尝试将确定树(模型)路径的逻辑与表示(将其绘制到CGContext
中)分开。生成树路径完全有可能是一项昂贵的操作,但至少通过将其与绘图分开,您可以避免阻塞主线程,并确保尽可能少地完成耗时的计算。