使用 CAShapeLayers 进行遮罩的动画和滚动性能严重滞后

Animation and Scrolling Performance Seriously Lagging Using CAShapeLayers for Masking

我问这个问题是不得已的方法,因为我找到并尝试过的任何解决方案都没有产生积极的结果。我正在设计一个应用程序,用户可以在其中操作 UIView 并制作由 UIBezierPath 定义的自定义形状。没有过多的细节,为了避免让你感到无聊,这基本上就是正在发生的事情:

override func drawRect(rect: CGRect) {

    // Create the path
    var path = UIBezierPath()

    // ...... The path is defined, set to be drawn in the view's frame

    // Draw the stroke of the actual path, close it and clip.
    path.lineWidth = 2.0
    UIColor.whiteColor().setStroke()
    path.stroke()
    path.closePath()
    path.addClip()

    // Create a CAShapeLayer to crop everything outside the path
    let maskForPath = CAShapeLayer()
    maskForPath.path = path.CGPath
    self.layer.mask = maskForPath
}

这样效果很好,随着用户继续使用该应用程序,他们会创建越来越多的形状,并且他们之前创建的形状会存储​​在 UIScrollView 中供他们查看,select稍后编辑。无论如何,一旦创建了多个形状(比如 15 个或更多),我使用 UIView.animateWithDuration 执行的任何动画都会变得非常不稳定,UIScrollView 内的滚动也是如此。这是令人沮丧的,因为在创建大量视图之前,一切都很好并且很流畅。此外,我尝试使用 touchesBegantouchesMoved 手动移动视图,当我以这种方式移动视图时它们移动得很好,没有滞后或任何东西。

到目前为止,我已经用尽了我能找到的所有解决方案。以下是我到目前为止尝试过的一些事情:

1) 一)layer.shouldRasterize = true

b) layer.rasterizationScale = UIScreen.mainScreen().scale

2) layer.drawsAsynchronously = true

3) AsyncDisplayKit

4) layer.allowsEdgeAntialiasing = true

None 这些解决方案产生了积极的结果。谁能想到我可能遗漏的任何东西,或者有解决这个问题的想法?这似乎不是内存问题,因为即使我在 UIScrollView 中嵌套了很多这些视图,我的应用程序平均也只使用 30mb 内存。此外,CPU 的影响似乎很小。我没有使用任何阴影,我已经尝试在 iPhone 5s、6 和 6s Plus 上进行测试,结果相同,所以这似乎不是设备的问题。希望有人能帮我找到解决方案,因为它让应用程序看起来像垃圾,而且据我所知,系统甚至没有被征税。

感谢您的帮助!提前致谢!

drawRect 有时会拖累性能。

因此我建议使用 CAShapeLayer 代替描边路径。

您可能需要为此创建一个新的形状层,因为您已经在使用当前的形状层进行遮罩。如果您 只是 想要描边(而不是填充),则需要将 strokeColor and lineWidth on it - as well as setting the fillColor 设置为 clearColor

然后您可以删除您的绘图代码 - 因此完全删除 drawRect(这应该会立即提升性能,因为 UIView 必须对自定义绘图进行额外处理)。您还应该发现您为优化它而尝试执行的所有上述操作应该会更好。

与 Core Graphics 绘图不同,Core Animation 能够利用 GPU - 因此通常在性能方面表现更好。

您还可以通过消除图层蒙版来显着提高您的性能。如果您的视图仅具有纯色背景色 - 您可以简单地在笔触形状图层上设置 fillColor 来实现这一点,然后放弃遮罩。

此外,正如一些相关答案所说,在多个子图层上将 shouldRasterize 设置为 true 有时会出现问题。您应该只在单个超级层上将其设置为 true

另一个 可能 改进性能的想法是将所有视图合并到一个视图中 - 并将您的路径合并到一个由子路径组成的路径中。然后,您可以使用遮罩和描边层显示此路径。