CoreGraphics (drawRect) 用于 UITableViewCell 中的绘图标签和 UIImageView



我有一个UITableViewCell,其中有5个UILabelUIButtonUIImageView,它们填充单元格作为背景。性能似乎有点慢,所以我想用CoreGraphics来改进它。用CoreGraphics代替UILabel作为subViews真的会更快吗?如果是,为什么?

我有以下代码来在单元格上绘制阴影:

[self.layer setBorderColor:[UIColor blackColor].CGColor];
[self.layer setShadowColor:[UIColor blackColor].CGColor];
[self.layer setShadowRadius:10.0];
[self.layer setCornerRadius:5.0];
[self.layer setShadowPath:[[UIBezierPath bezierPathWithRect:self.frame] CGPath]];

一般来说,(正如Gavin所指出的)我认为您必须首先确认子视图确实导致了滚动中的抖动。

当我测试UITableViewCell滚动性能时,我经常在Instruments中使用时间档案器。切换到左侧面板中的Objective-C Only,看看在主线程上花费最多时间的是什么。如果您看到在重新排列(布局)或绘制子视图上花费了大量时间,则可能需要使用CoreGraphics。如果时间花在分配/解除分配上,那么您可能需要检查子视图是如何重用的(如果有的话)。如果它们没有被重用,那么这当然会导致性能问题。

当然,你应该看看合成。如果子视图不是不透明的(通过CoreAnimation工具识别),则性能可能会受到严重影响。

同样需要注意的是,要意识到阴影的绘制成本很高,而且根据您的实现,它们可能会在每一帧上重新绘制!您的最佳选择是确保任何CALayer阴影都已完全光栅化,并定义了路径,这样就不必从像素遮罩进行实时计算。

如果最后,你发现每个子视图的布局和重新绘制是导致速度减慢的原因,那么我有几个观点/解释:

  1. 您的表视图单元格绘图例程的实现可能会比Apple为其视图编写的高度优化的绘图慢。因此,重新实现UIImageView本身的绘制不会赢得任何战斗。相反,使用CoreGraphics绘制时,性能提升来自两个方面:a.)预先渲染以前非不透明的视图,并减少视图绘制周期的布局阶段所花费的时间-这减少了滚动时GPU/CPU的工作量。b.)减少单个视图绘图的CG上下文切换时间。现在,每个元素都同时绘制到相同的图形上下文中,从而降低了切换成本。

  2. 在drawRect中使用主线程上的CoreGraphics绘制使用CPU绘制,根据单元格的复杂程度,这可能会导致自身的抖动。相反,可以考虑在后台线程中绘制到单独的CGContext,然后派遣一名工作人员将绘图内容作为CGImageRef插入到CALayer中,或者作为UIImageView中的UIImage插入。GitHub上有一个天真的实现:https://github.com/mindsnacks/MSCachedAsyncViewDrawing

  3. 如果你决定使用背景CoreGraphics绘图,请注意,目前(2012年12月),我认为在背景线程上绘图时,NSString绘图类别中存在一个错误,导致回退到绝对不安全的webkit。这将导致崩溃,因此目前请确保异步绘图是在串行GCD/NSOperation队列中完成的。

在模拟器上,Debug颜色混合层。红色是坏的,绿色是好的。

更准确地说,红色表示GPU需要进行alpha混合。主要成本是绘制两次像素并可能重新获取额外纹理所需的内存带宽。完全透明的像素真的很糟糕。

三个修复(所有这些都减少了红色的数量),在深入核心图形之前应该考虑:

  • 尽可能使视图不透明。背景设置为[UIColor clearColor]的标签通常可以设置为单色
  • 使具有透明度的视图尽可能小。对于标签,这涉及到使用-sizeToFit/-sizeThatFits:并适当调整布局
  • 从不透明图像中移除alpha通道(例如,如果您的单元格背景是图像)—一些图像编辑器不这样做,这意味着GPU需要执行alpha测试,并且可能需要渲染图像背后的任何内容

此外,启用和"屏幕外渲染的颜色">(可能是在禁用"颜色混合层"之后,以便更容易查看)。屏幕外渲染的内容显示为黄色,通常意味着您已经应用了层遮罩。这些可能对性能非常不利;我不知道CoreAnimation是否缓存了遮罩的结果。

最后,您可以通过设置cell.layer.shouldRasterize = YES使CoreAnimation光栅化细胞(您可能还需要在视网膜设备上使用cell.layer.rasterizationScale = [[UIScreen mainScreen].scale;我忘记了这是否是自动完成的)。主要好处是它很容易,而且比自己在Core Graphics中渲染图像视图更高效。(由于文本需要在CPU上呈现,标签的好处减少了。)

还要注意,视图动画将受到影响。我忘记了设置CALayer.shouldRasterize的作用(它可能会在动画的每一帧重新光栅化它,当它只被绘制到屏幕上一次时,这有点浪费),但使用核心图形会(默认情况下)在动画过程中拉伸渲染的内容。参见CALayer.conttsGravity。

您有什么证据表明视图中的内容导致了性能问题?这是一个很深的黑洞,可以把你吸进去,所以一定要知道问题出在你认为的地方

您是否正在预加载所有数据?你已经预先下载了这些图片吗?您所描述的内容不应该导致UITableViewCell的速度减慢。苹果开发人员比你和我聪明得多,所以请确保你有数据支持你的决定!

我还在模拟器中看到了一个滞后的UITableViewCell,在实际硬件上没有明显的差异。

的确,使用CoreGraphics可以提高绘图性能,但如果你做错了,它也会减慢绘图速度!查看Apple高级表视图单元格教程,了解如何执行该技术。

最新更新