@qixingguaizhuang
2016-04-19T12:06:15.000000Z
字数 2189
阅读 1188
项目中我们会用到头像或是在视图展示时,设置“友好”“不尖锐”的圆角,进行美化,当视图的渲染帧率低于 40 帧每秒,普通用户就会察觉明显的不流畅了。视图和圆角的大小对帧率的影响微乎其微,真正影响帧率的是圆角图片的数量,数量越多,对于性能的影响是非常大的。
通常我们设置头像圆角的方法:
yourImageView.layer.cornerRadius = aImageView.frame.size.width/2.0;
yourImageView.layer.masksToBounds = YES;
使用这个方法会造成 Off-Screen Rendering(离屏渲染)。频繁发生离屏渲染是非常耗时的,所以会造成帧率会下降,造成卡顿的情况,对性能上造成影响。
Off-Screen Rendering
离屏渲染,指的是GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。道离屏渲染耗时是发生在离屏这个动作上面,而不是渲染。为什么离屏这么耗时?原因主要有创建缓冲区和上下文切换。创建新的缓冲区代价都不算大,付出最大代价的是上下文切换。
上下文切换
上下文切换,不管是在GPU渲染过程中,还是一直所熟悉的进程切换,上下文切换在哪里都是一个相当耗时的操作。首先我要保存当前屏幕渲染环境,然后切换到一个新的绘制环境,申请绘制资源,初始化环境,然后开始一个绘制,绘制完毕后销毁这个绘制环境,如需要切换到On-Screen Rendering或者再开始一个新的离屏渲染重复之前的操作。 下图描述了一次mask的渲染操作。
批注: 离屏渲染上下文,个人理解,视图切换,会发生离屏渲染,造成耗费时间,影响性能。
一次mask发生了两次离屏渲染和一次主屏渲染。即使忽略昂贵的上下文切换,一次mask需要渲染三次才能在屏幕上显示,这已经是普通视图显示3陪耗时,若再加上下文环境切换,一次mask就是普通渲染的30倍以上耗时操作。问我这个30倍以上这个数据怎么的出来的?当我在cell的UIImageView的实例增加到150个,并去掉圆角的时候,帧数才跌至28帧每秒。虽然不是甚准确,但至少反映mask这个耗时是无mask操作的耗时的数十倍的。
解决方案:
//设置圆角视图样式
-(void)setUpSelfView{
//阴影 Shadow
self.layer.shadowColor = [UIColor blackColor].CGColor; //黑
self.layer.shadowOpacity = 0.33;//阴影的不透明度
self.layer.shadowOffset = CGSizeMake(0, 1.5);//阴影的偏移
self.layer.shadowRadius = 4.0;//阴影半径
self.layer.shouldRasterize = YES; //圆角缓存
self.layer.rasterizationScale = [UIScreen mainScreen].scale;//提高流畅度
//圆角
self.layer.cornerRadius = 10.0f;
}
这样大部分情况下可以马上挽救你的帧数在55帧每秒以上。shouldRasterize = YES会使视图渲染内容被缓存起来,下次绘制的时候可以直接显示缓存,当然要在视图内容不改变的情况下。
除了上面非要作死的人外,大家还是采取预先生成圆角图片,并缓存起来这个方法才是比较好的手段。预处理圆角图片可以在后台处理,处理完毕后缓存起来,再在主线程显示,这就避免了不必要的离屏渲染了。
另外也有在图片上面覆盖一个镂空圆形图片的方法可以实现圆形头像效果,这个也是极为高效的方法。缺点就是对视图的背景有要求,单色背景效果就最为理想。
使用贝塞尔曲线绘制
- (UIImage *)imageWithCornerRadius:(CGFloat)radius {
CGRect rect = (CGRect){0.f, 0.f, self.size};
UIGraphicsBeginImageContextWithOptions(self.size, NO, UIScreen.mainScreen.scale);
CGContextAddPath(UIGraphicsGetCurrentContext(), [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius].CGPath);
CGContextClip(UIGraphicsGetCurrentContext());
[self drawInRect:rect];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
总结
实现圆角cornerRadius要比mask高效很多。Rasterize在大部分情况下极大减少GPU工作。在有空间的情况下,大部分情况下缓存总能帮到你,不是吗?后台预处理图片也能很简单帮上你很大的忙。
感谢:
http://www.cocoachina.com/ios/20150803/12873.html
http://blog.csdn.net/qxuewei/article/details/50953950