提高自定义 UIView 的绘图性能

发布于 2024-09-13 17:33:28 字数 579 浏览 2 评论 0原文

我有一个自定义的 UIView,它由许多图像组成,它们的位置随着用户触摸而变化。 该视图必须跟踪用户触摸,而我在绘制此类视图时遇到性能瓶颈,导致我无法实时跟踪输入。

一开始,我在 [UIView drawRect:] 方法中绘制所有内容,当然它太慢了,因为即使没有必要,所有内容都会重新绘制。 然后,我使用更多的 CALayers 来仅更新正在更改的层,这给了我更好的响应能力。 但是,当我必须在一个图层上多次绘制相同的图像时,最多需要 500 毫秒。

由于图像放置在固定位置,是否有办法预先绘制它们?我是否应该考虑将它们放入多个 CALayers 中并隐藏/显示它们? 另外,我不明白为什么存在 [CALayer setNeedsDisplayInRect:] 但委托(显然)无法知道无效的矩形是什么来优化绘图。


解决方案

按照答案中的建议,我最终为图像创建了许多 CALayers,并在第一次显示图层时设置了 contents 属性。这是一种延迟加载的妥协:在第一次尝试中,我在创建时设置了每个图层的内容,但这导致在程序启动时预先绘制任何可能的图像,从而将应用程序冻结几秒钟。

I have a custom UIView which is composed of many images, their positions are changing in response to the user touch.
The view must track the user touch and i'm experiencing a performance bottleneck in the drawing of such view, preventing me to follow the input in realtime.

At the beginning i was drawing everything in the [UIView drawRect:] method and of course it was way too slow because everything was redrawn even if not necessary.
Then, i used more CALayers to update only the layer that was changing and this gave me much better responsiveness.
But still, when i have to draw the same image many times on a layer it takes up to 500ms.

Since the images are placed at fixed positions it there a way to pre-draw them? Should i consider putting them in many CALayers and just hide/show them?
Also, i don't understand why a [CALayer setNeedsDisplayInRect:] exists but the delegate has (apparently) no way to know what the invalid rect is to optimize the drawing.


Solution

Following the advice in the answer I finally created many CALayers for the images and set the contents property the first time the layer was being shown. This is a lazy-loading compromise: in a first attempt i set the contents of every layer at the creation time but this caused to pre-draw any possible image on the program launch, freezing the application for seconds.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一个人的旅程 2024-09-20 17:33:28

来自 -[CALayer drawInContext:] 的文档:

默认实现不执行任何操作。可以剪裁上下文以保护有效的层内容。希望找到实际绘制区域的子类可以调用 CGContextGetClipBoundingBox。当内容属性更新时由显示方法调用。

显示的默认实现在自动创建的上下文上调用drawInContext:;大概也设置了边界框(大概被传递给drawRect:)。

如果您要绘制多张静态图像,我只需将每张图像粘贴到其自己的 UIView 中即可;我不认为开销有那么大(如果是的话,CALayer 开销应该更小)。如果它们都有动画,我肯定会使用 UIView/CALayer。如果其中一些动画没有(太多)并且您发现速度明显缓慢,则可以预渲染它们。这是在drawRect:(或类似的)中渲染和GPU上的图层合成之间的权衡,但总的来说,我认为后者要快得多。

From the documentation for -[CALayer drawInContext:]:

Default implementation does nothing. The context may be clipped to protect valid layer content. Subclasses that wish to find the actual region to draw can call CGContextGetClipBoundingBox. Called by the display method when the contents property is being updated.

The default implementation of display calls drawInContext: on an automatically-created context; presumably setting the bounding box as well (which is presumably passed to drawRect:).

If you're drawing several static images, I'd just stick each one in its own UIView; I don't think the overhead is that big (if it is, the CALayer overhead should be smaller). If they all animate, I'd definitely use UIView/CALayer. If some of them don't animate (much) and you notice significant slowness, you can pre-render those. It's a trade-off between rendering in drawRect: (or similar) and layer compositing on the GPU, but in general I'd assume that the latter is much faster.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文