RounderCorner)是一种很常见的视图效果,相比于直角,它更加柔和优美,易于接受。当然,设置圆角会带来一定的性能损耗,如何提高性能是另一个需要重点讨论的话题。

一、如何设置圆角

通常label.layer.cornerRadius=x就可以设置圆角,但是cornerRadius只会影响视图的背景颜色和border,对于内部还有子视图的控件就会设置不成功(如UILabel),对于内部还有子视图的控件还需要设置label.layer.masksToBounds=true才能使cornerRadius属性生效,此时会造成离屏渲染。

二、设置圆角的性能损耗

经大神代码测试,设置圆角时masksToBounds的使用会降低手机每秒刷新的帧数,特别是在tableview中设置圆角时帧率下降非常快,帧率下降直接造成界面的不流畅。设置圆角拖慢帧率的原因是设置圆角会发生Off-Screen Rendering(离屏渲染),离屏渲染是个好东西,但是频繁发生离屏渲染是非常耗时的。大神原博客网址:http://www.cocoachina.com/ios/20150803/12873.html

Off-Screen Rendering

GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。视图和圆角的大小对帧率并没有什么影响,设置圆角的数量才是影响帧率的原因。离屏渲染耗时是发生在离屏这个动作上面,而不是渲染。为什么离屏这么耗时?原因主要有创建缓冲区和上下文切换。创建新的缓冲区代价都不算大,付出最大代价的是上下文切换。不管是在GPU渲染过程中,还是进程切换,上下文切换都是一个相当耗时的操作。首先我要保存当前屏幕渲染环境,然后切换到一个新的绘制环境,申请绘制资源,初始化环境,然后开始一个绘制,绘制完毕后销毁这个绘制环境,如需要切换到On-Screen Rendering或者再开始一个新的离屏渲染重复之前的操作。 

三、设置圆角造成频率下降的解决方案

方案一:不要在滚动视图使用cornerRadius或者mask,如果你非要作死怎么办呢?那么这样也可以拯救你:

1

2

self.layer.shouldRasterize = YES;  

self.layer.rasterizationScale = [UIScreen mainScreen].scale;

这样大部分情况下可以马上挽救你的帧数在55帧每秒以上。shouldRasterize = YES会使视图渲染内容被缓存起来,下次绘制的时候可以直接显示缓存,当然要在视图内容不改变的情况下。

方案二:除了上面非要作死的人外,大家还是采取预先生成圆角图片,并缓存起来这个方法才是比较好的手段。预处理圆角图片可以在后台处理,处理完毕后缓存起来,再在主线程显示,这就避免了不必要的离屏渲染了。

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

UIImageView 的圆角通过直接截取图片实现,其它视图的圆角可以通过 Core Graphics 画出圆角矩形实现。==大神在博客中已经给出了代码参考,大神博客:http://www.cocoachina.com/ios/20160301/15486.html

总结

  • 如果能够只用 cornerRadius 解决问题,就不用优化。
  •  masksToBounds,可以参考圆角视图的数量,如果数量较少(一页只有几个)也可以考虑不用优化。