关于CALayer 的速度

2012-05-09 00:02:53 +08:00
 adow
最近在做的一个项目中,需要在UITableViewCell中的UIImageView中显示头像,他们是32*32的正方形小图片,为了实现圆角的效果,我给这个UIImageView设置了CALayer的几个相关属性:

self.imgAvator.layer.cornerRadius=3.0;
self.imgAvator.layer.borderWidth=1.0;
self.imgAvator.layer.borderColor=[UIColor colorWithRed:0 green:0 blue:0 alpha:0.05].CGColor;
self.imgAvator.clipsToBounds=YES;

当然他很好的实现了圆角的效果;

可是在实际运行中,我发现这个UITableView的滚动速度不是很理想,在排除了其他我感觉可能引起的问题之后,我去掉了这个layer的代码,感觉速度有明显的提升了。

然后,我没有使用layer来实现圆角,而是在获取UIImage后直接做了处理剪裁出圆角图片,这时速度依然比使用layer的明显要快。

所以我想问的是,使用CALayer的绘图会影响UI的速度吗,有啥优化的办法没有呢?
9571 次点击
所在节点    iDev
15 条回复
Sai
2012-05-09 00:17:17 +08:00
Try layer.shouldRasterize = YES;
txx
2012-05-09 05:24:56 +08:00
我一直觉得coreanimation的效率非常不错

lz您不会是cell没写好吧。。
adow
2012-05-09 11:06:17 +08:00
@Sai 我用了layer.shouldResterize=YES,速度好像没有明显的改善啊,所以现在还是直接在UIImage上处理之后比较流畅;
@txx 我也怀疑cell哪里写的有问题,我检查了一些地方,cell reuse 是正常工作的,table的数据现在是从本地的缓存里加载的,我去掉了头像以外所有的数据显示,没有明显的改善,只有去掉layer的几句代码才让我突然感受到流畅不少了,所以我才怀疑这个问题。
dongsheng
2012-05-09 11:13:41 +08:00
有没有试试直接把图片直接画到cell的CALayer上?额外用UIImageView肯定要消耗更多资源。
adow
2012-05-09 11:15:09 +08:00
google 了一下CALayer,看到了 @livid 的这个http://picky.olivida.com/calayer-and-ipad-apps-performance

> 每一个 UIView 对象实例都包含一个 CALayer 实例,可以通过 [myView layer] 的方式访问到。而 CALayer 又提供了非常多的邪恶功能,比如修改一个 view 的圆角程度,甚至给它加阴影。这些方法都非常好用。但是代价就是程序的 framerate 就会大受影响,尤其是执行诸如 presentModalViewController 这样全屏幕豪华操作时。

结论是:要用 CALayer 可以,但是在写到屏幕上之前一定要先将这个 layer 的内容变成一坨简单的 bitmap,否则就等着看幻灯片吧。
jesse0628
2012-05-09 11:43:13 +08:00
跟楼主体会完全一样,我一直找不到原因,为什么我的添加到scroll view里面的东西会滚起来那么卡,原因大概还是我里面用了很多CALayer圆角的东西,也做了一些CALayer比如绘制什么的操作。但是应该最大的问题是圆角引起的。
senopanas
2012-05-09 11:45:14 +08:00
clipsToBounds=YES实际上还多了一个step跳转到masksToBounds=YES,效果当然都一样:
-(BOOL)[UIView(Rendering) clipsToBounds]
+0 3091938a 55 pushl %ebp
+1 3091938b 89e5 movl %esp,%ebp
+3 3091938d e800000000 calll 0x30919392
+8 30919392 59 popl %ecx
+9 30919393 8b4508 movl 0x08(%ebp),%eax
+12 30919396 8b5004 movl 0x04(%eax),%edx (CALayer)_layer
+15 30919399 8b8186cb1301 movl 0x0113cb86(%ecx),%eax masksToBounds
+21 3091939f 89450c movl %eax,0x0c(%ebp)
+24 309193a2 895508 movl %edx,0x08(%ebp)
+27 309193a5 c9 leave
+28 309193a6 e92e211801 jmpl 0x31a9b4d9

不过至少可以省一步,shouldResterize效果不大但是有效果。一般来说在cell上添加一个CAlayer的圆角并且masksToBounds也不会降低多少performance,你的头像图片是lazy loading吗?
mr_pppoe
2012-05-09 11:59:42 +08:00
隐约记得有一段WWDC的视频讨论了类似的问题
adow
2012-05-09 12:01:02 +08:00
@senopanas 头像是异步http下载的,我现在是下载完后处理成圆角的UIImage后赋值到imgAvator.image上
adow
2012-05-09 12:04:07 +08:00
哦对了,实际运行中,因为头像部分的http请求做了缓存,所以大部分是本地读取的文件,跳过http请求的
elden
2012-05-09 12:30:58 +08:00
直接设置cornerRadius会影响滚动的流畅性。如果cell不使用复杂背景,那可以在头像上覆盖一层空心的圆角图片。
ultragtx
2012-05-09 12:45:08 +08:00
CALayer直接setCornerRadius会发生offscreen rendering,简单地说就是在屏幕外渲染一遍,接着再渲染到屏幕上(涉及到多开一个屏幕外buffer,屏幕内buffer和屏幕外buffer来回切换等问题),CoreAnimation是逐帧渲染的,所以scroll的时候每帧都进行这个操作,结果就很慢,解决方法一般就是先把圆角图片画出来。
一楼Sai那个方法就是缓存offscreen render,这样就不用每帧都渲染一遍,但是要求layer的内容是不变的,如果有变化还是要慢,不过你这个情况应该符合。

具体参考WWDC 2011 Session 121 这个讲的特别细
adow
2012-05-09 12:52:27 +08:00
感谢大家的讨论,我之前一直都不知道这些。
keakon
2012-05-11 20:55:36 +08:00
最好不要用 UIImageView 和 CALayer,比直接显示肯定要慢的。另外可以用预渲染:
http://www.keakon.net/article/96200
http://www.keakon.net/article/98200
hydyy
2012-12-07 21:56:10 +08:00
哈喽~ 楼主您解决这个问题了嘛? 我也遇到了~~哈哈阿红

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/35173

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX