UIBezierPath的快速替代品

时间:2019-04-04 14:19:32

标签: swift core-graphics uibezierpath

我正在制作可以构建图形的应用程序。 我正在使用UIBezierPath,在我决定使用手势移动和缩放图形之前,一切都很好。

这是我的绘画方式:

var isFirstPoint = true
        color.set()
        funcPath.lineWidth = width

        for i in 0...Int(bounds.size.width * contentScaleFactor) {
            let cgX = CGFloat(i) / contentScaleFactor
            let funcX = Double ((cgX - bounds.width / 2) / scale)

            let funcY = function(funcX) * Double(scale)

            guard !funcY.isNaN else { continue }
            let cgY = -( CGFloat(funcY) - bounds.height / 2)

            if isFirstPoint {
                funcPath.move(to: CGPoint(x: cgX, y: cgY))
                isFirstPoint = false
            } else {
                if cgY > max(bounds.size.width, bounds.size.height) * 2 {
                    isFirstPoint = true
                } else {
                    funcPath.addLine(to: CGPoint(x: cgX, y: cgY) )
                }
            }
        }
funcPath.stroke()

有没有更快的方法呢?

3 个答案:

答案 0 :(得分:1)

通常,通过对图层进行变换来完成移动和缩放。查看CAShapeLayer以保持您的前进方向。当用户手势时,应用变换;然后在手势完成后重新创建路径。在更高级的用法中,您可能会重新计算实际路径,而不仅仅是在用户停止时(例如,他们暂停但不放手),而是重新计算实际路径。

答案 1 :(得分:1)

一些想法:

  1. 为每个像素重建路径可能是一个昂贵的过程。降低成本的一种方法是减少渲染的数据点数量。例如,如果您要调整scale并重建整个路径,则在更新路径中间手势时可能需要使用一些step因子,并将for循环替换为:

    let step = 4
    for i in stride(from: 0, through: Int(bounds.size.width * contentScaleFactor), by: step) {
        ...
    }
    

    然后,手势结束时,您可以使用step的{​​{1}}再更新一次路径。

  2. 另一种方法是更新1并每次都调用scale,而只是更新setNeedsDisplay视图。 (这在放大时会导致超快的行为,但在缩小时显然会出现问题,因为不会渲染路径中排除的部分。)

  3. 如果要对此进行测试,请确保测试在物理设备上构建的版本(即经过优化)。调试版本及其所有的安全检查,实际上会减慢该过程的速度,而这种过程将在计算强度方面如此突出。

  4. 顺便说一句,看起来路径的构建被埋在transform中。我会将draw(rect:)的构建与路径的绘制分离,因为是的,每次更新函数时,您可能都想更新并绘制路径,所以您绝对不希望重新构建每次调用UIBezierPath时的路径。

  5. 执行此操作后,可能甚至不需要draw(rect:)。您可能只需添加一个draw(rect:)作为视图层的子层,设置该形状层的CAShapeLayerstrokeColor,然后更新其strokeWidth

    < / li>

答案 2 :(得分:0)

如果您能够将翻译(平移)描述为CGAffineTransform,则可以使用apply(_:)一次将其应用于UIBezierPath