转载:当心别让圆角成了你列表的帧数杀手

前言
在iOS的世界,圆角无处不在,并且必须存在。由于圆角是符合人类视觉安全体验的,圆角让人以为温馨,而方角在潜意识层次是具备伤害体验的,由于尖尖的东西老是有可能对人形成伤害的,因此咱们更喜欢圆角。在我以前的文章中讲过,在iOS的中设置圆角是很是容易的一件事情,这也体现出苹果也是很是重视圆角这件事情的。缓存

圆角虽好,但若是使用不当,它就是你的帧数杀手,特别当它出如今滚动列表的时候。下面来看圆角如何毁掉你的流畅度的。安全

实测
layer.cornerRadius
我建立了一个简单地UITableView视图,为每一个cell添加了2个UIImageView实例,且为UIImageView实例进行以下设置app

aImageView.layer.cornerRadius = aImageView.frame.size.width/2.0;
aImageView.layer.masksToBounds = YES;性能

大家猜,如今滚动的帧率是多少。测试

已经跌至45帧每秒,这个帧率已经让人感受到不那么顺滑了,若是低于40帧每秒,普通用户就会察觉明显的不流畅了。当我把cell的UIImageView实例增长至四个线程

如今帧率已经低于30帧每秒了进程

这个帧率若是出如今首屏,足以引领你的app进入垃圾级别的体验了。 如今我把UIImageView实例的size调的小一些。图片

平均帧率提升了大概3帧每秒。资源

在这里视图和圆角的大小对帧率并无什么卵影响,数量才是伤害的核心输出啊。get

layer.mask
以前有的文章说经过layer.cornerRadius和layer.mask设置圆角并无什么差别,事实真的是这样的吗?我以下设置了圆角:

CAShapeLayer *layer = [CAShapeLayer layer];
UIBezierPath *aPath = [UIBezierPath bezierPathWithOvalInRect:aImageView.bounds];
layer.path = aPath.CGPath;
aImageView.layer.mask = layer;
获得的帧率以下:

居然只有20帧每秒了,比layer.cornerRadius还少了8帧!!!因此layer.cornerRadius实现圆角的性能是要比layer.mask要高不少。

maskView
iOS的UIView多了一个maskView方法,不过这个东西和layer.mask是一个卵样的。

原理
上面拖慢帧率的缘由其实都是Off-Screen Rendering(离屏渲染)的缘由。离屏渲染是个好东西,可是频繁发生离屏渲染是很是耗时的。

Off-Screen Rendering
离屏渲染,指的是GPU在当前屏幕缓冲区之外新开辟一个缓冲区进行渲染操做。由上面的一个结论视图和圆角的大小对帧率并无什么卵影响,数量才是伤害的核心输出啊。能够知道离屏渲染耗时是发生在离屏这个动做上面,而不是渲染。为何离屏这么耗时?缘由主要有建立缓冲区和上下文切换。建立新的缓冲区代价都不算大,付出最大代价的是上下文切换。

上下文切换
上下文切换,不论是在GPU渲染过程当中,仍是一直所熟悉的进程切换,上下文切换在哪里都是一个至关耗时的操做。首先我要保存当前屏幕渲染环境,而后切换到一个新的绘制环境,申请绘制资源,初始化环境,而后开始一个绘制,绘制完毕后销毁这个绘制环境,如须要切换到On-Screen Rendering或者再开始一个新的离屏渲染重复以前的操做。 下图描述了一次mask的渲染操做。

一次mask发生了两次离屏渲染和一次主屏渲染。即便忽略昂贵的上下文切换,一次mask须要渲染三次才能在屏幕上显示,这已是普通视图显示3陪耗时,若再加上下文环境切换,一次mask就是普通渲染的30倍以上耗时操做。问我这个30倍以上这个数据怎么的出来的?当我在cell的UIImageView的实例增长到150个,并去掉圆角的时候,帧数才跌至28帧每秒。虽然不是甚准确,但至少反映mask这个耗时是无mask操做的耗时的数十倍的。

应对
那么如何应对这个问题呢?不要在滚动视图使用cornerRadius或者mask。若是你非要做死怎么办呢?那么这样也能够拯救你:

self.layer.shouldRasterize = YES;
self.layer.rasterizationScale = [UIScreen mainScreen].scale;
这样大部分状况下能够立刻挽救你的帧数在55帧每秒以上。shouldRasterize = YES会使视图渲染内容被缓存起来,下次绘制的时候能够直接显示缓存,固然要在视图内容不改变的状况下。

除了上面非要做死的人外,你们仍是采起预先生成圆角图片,并缓存起来这个方法才是比较好的手段。预处理圆角图片能够在后台处理,处理完毕后缓存起来,再在主线程显示,这就避免了没必要要的离屏渲染了。

另外也有在图片上面覆盖一个镂空圆形图片的方法能够实现圆形头像效果,这个也是极为高效的方法。缺点就是对视图的背景有要求,单色背景效果就最为理想。

总结
实现圆角cornerRadius要比mask高效不少。
Rasterize在大部分状况下极大减小GPU工做。在有空间的状况下,大部分状况下缓存总能帮到你,不是吗?
后台预处理图片也能很简单帮上你很大的忙。
(以上测试数据来自于iPhone5。)


原文连接:当心别让圆角成了你列表的帧数杀手

相关文章
相关标签/搜索