问题

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

实测

layer.cornerRadius

我创建了一个简单地UITableView视图,为每个cell添加了2个UIImageView实例,且为UIImageView实例进行如下设置

aImageView.layer.cornerRadius = aImageView.frame.size.width/2.0;

aImageView.layer.masksToBounds = YES;

运行截图如下:

 

你们猜,现在滚动的帧率是多少。

 

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

 

现在帧率已经低于30帧每秒了

 

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

 

平均帧率提高了大概3帧每秒。

 

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

原理

上面拖慢帧率的原因其实都是Off-Screen Rendering(离屏渲染)的原因。离屏渲染是个好东西,但是频繁发生离屏渲染是非常耗时的。

Off-Screen Rendering

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

上下文切换

上下文切换,不管是在GPU渲染过程中,还是一直所熟悉的进程切换,上下文切换在哪里都是一个相当耗时的操作。首先我要保存当前屏幕渲染环境,然后切换到一

个新的绘制环境,申请绘制资源,初始化环境,然后开始一个绘制,绘制完毕后销毁这个绘制环境,如需要切换到On-Screen

Rendering或者再开始一个新的离屏渲染重复之前的操作。 下图描述了一次mask的渲染操作。

 

一次mask发生了两次离屏渲染和一次主屏渲染。即使忽略昂贵的上下文切换,一次mask需要渲染三次才能在屏幕上显示,这已经是普通视图显示3陪耗时,若

再加上下文环境切换,一次mask就是普通渲染的30倍以上耗时操作。问我这个30倍以上这个数据怎么的出来的?当我在cell的UIImageView

的实例增加到150个,并去掉圆角的时候,帧数才跌至28帧每秒。虽然不是甚准确,但至少反映mask这个耗时是无mask操作的耗时的数十倍的。

第一种:设置CALayer的cornerRadius

 imageView.image = [UIImage imageNamed:@"img"];
imageView.image.layer.cornerRadius = 5;
imageView.image.layer.masksToBounds = YES;

这样设置会触发离屏渲染,比较消耗性能。比如当一个页面上有十几头像这样设置了圆角

会明显感觉到卡顿。
这种就是最常用的,也是最耗性能的。

注意:ios9.0之后对UIImageView的圆角设置做了优化,UIImageView这样设置圆角
不会触发离屏渲染,ios9.0之前还是会触发离屏渲染。而UIButton还是都会触发离屏渲染。

第二种

imageView.clipsToBounds = YES;
imageView.layer setCornerRadius:50];
imageView.layer.shouldRasterize = YES;

shouldRasterize=YES设置光栅化,可以使离屏渲染的结果缓存到内存中存为位图, 使用的时候直接使用缓存,节省了一直离屏渲染损耗的性能。

但是如果layer及sublayers常常改变的话,它就会一直不停的渲染及删除缓存重新 创建缓存,所以这种情况下建议不要使用光栅化,这样也是比较损耗性能的。

第三种 :通过Core Graphics重新绘制带圆角的视图

这种方式性能最好,但是UIButton上不知道怎么绘制,可以用UIimageView添加个 点击手势当做UIButton使用

@implementation UIImage (CircleImage)

- (UIImage *)drawCircleImage {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, [UIScreen mainScreen].scale);
   [[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:50] addClip];
[self drawInRect:self.bounds];
UIImage *output = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();
   return output; 
}
@end
//在需要圆角时调用如下
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *img = [[UIImage imageNamed:@"image.png"] drawCircleImage];
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = img;
});
});

四、通过混合图层

此方法就是在要添加圆角的视图上再叠加一个部分透明的视图,只对圆角部分进行遮挡。图层混合的透明度处理方式与mask正好相反。此方法虽然是最优解,没有离屏渲染,没有额外的CPU计算,但是应用范围有限。


总结

  1. 在可以使用混合图层遮挡的场景下,优先使用第四种方法。
  2. 即使是非iOS9以上系统,第一种方法在综合性能上依然强于后两者,iOS9以上由于没有了离屏渲染更是首选。
  3. 方法三由于需要大量计算和增加部分内存,需要实际情况各自取舍。
 

iOS图片设置圆角性能优化的更多相关文章

  1. iOS图片设置圆角

    一般我们在iOS开发的过程中设置圆角都是如下这样设置的. imageView.clipsToBounds = YES; [imageView.layer setCornerRadius:]; 这样设置 ...

  2. Java 图片设置圆角(设置边框,旁白)

    /** * 图片设置圆角 * @param srcImage * @param radius * @param border * @param padding * @return * @throws ...

  3. iOS进阶之页面性能优化

    转载:http://www.jianshu.com/p/1b5cbf155b31 前言 在软件开发领域里经常能听到这样一句话,"过早的优化是万恶之源",不要过早优化或者过度优化.我 ...

  4. iOS开发系列之性能优化(上)

    本篇主要记录一下我对界面优化上的一些探索.关于时间优化的探索将会在中篇里进行介绍.下篇将主要介绍一些耗电优化.安装包瘦身的探索. ### 1.卡顿原理 要了解卡顿原理,需要对帧缓冲区.垂直同步.CPU ...

  5. iOS 图片加载速度优化

    FastImageCache 是 Path 团队开发的一个开源库,用于提升图片的加载和渲染速度,让基于图片的列表滑动起来更顺畅,来看看它是怎么做的. 一.优化点 iOS 从磁盘加载一张图片,使用 UI ...

  6. BeagleBone Black Industrial 进阶设置(性能优化以及延长板载eMMC存储寿命)

    前言 原创文章,转载引用务必注明链接.水平有限,欢迎指正. 本文使用markdown写成,为获得更好的阅读体验,推荐访问我的博客原文: http://www.omoikane.cn/2016/09/1 ...

  7. iOS UIView设置圆角

    UIView设置圆角 1.比较简单的情况,UIView四个角都是圆角: UIView *aView = [[UIView alloc] init]; aView.frame = CGRectMake( ...

  8. IOS学习笔记45--UITableView性能优化

    说实话,面试的时候已经被问到几次这个问题,然后就搜索了一下,看到了这篇优化文章,感觉不错,转来日后作为一种UITableView优化的方法. 使用不透明视图.      不透明的视图可以极大地提高渲染 ...

  9. Vue回炉重造之图片加载性能优化

    前言 图片加载优化对于一个网站性能好坏起着至关重要的作用.所以我们使用Vue来操作一波.备注 以下的优化一.优化二栏目都是我自己封装在Vue的工具函数里,所以请认真看完,要不然直接复制的话,容易出错的 ...

随机推荐

  1. li分两列显示

    只要控制了li的宽度,利用浮动就能实现<style type="text/css"> .my ul { width: 210px; } .my li { width: ...

  2. Java面试题系列(一)描述一下JVM加载class文件的原理机制

    JVM系列第4讲:从源代码到机器码,发生了什么? https://www.cnblogs.com/chanshuyi/p/jvm_serial_04_from_source_code_to_machi ...

  3. go语言学习之路(一)Hello World

    为什么要使用 Go 语言?Go 语言的优势在哪里? 1.部署简单. 2.并发性好. 3.良好的语言设计. 4.执行性能好. Go环境搭建 Golang下载 国外镜像  https://www.gola ...

  4. Value = undefined

    Value = undefined Javascript在计算机程序中,经常会声明无值的变量.未使用值来声明的变量,其值实际上是 undefined. 在执行过以下语句后,变量 carname 的值将 ...

  5. c# 防止sql注入对拼接sql脚本的各个参数处理

    调用方法:GameServerId = this.NoHtml(GameServerId);//GameServerId为一个拼接sql的参数 /// <summary> /// 过滤标记 ...

  6. Verilog笔记.三段式状态机

    之前都是用的一段式状态机,逻辑与输出混在一起,复杂点的就比较吃力了. 所以就开始着手三段式状态机. 组合逻辑与时序逻辑分开,这样就能简单许多了. 但是两者在思考方式上也有着很大的区别. 三段式,分作: ...

  7. [SDOI2009]HH去散步 「矩阵乘法计数」

    计数问题也许可以转化为矩阵乘法形式 比如若该题没有不能在一条边上重复走的条件限制,那么直接将邻接矩阵转化为矩阵乘法即可 故 矩阵乘法计数 对于计数问题,若可以将 \(n\) 个点表示成 \(n \ti ...

  8. php的递归函数示例

    递归函数太难理解了,写了一个示例放在这里方便没事的时候看一下. <?php /** *php递归函数示例 *(从1到100的累加和计算) * */ function summation($num ...

  9. android 调用系统照相机拍照后保存到系统相册,在系统图库中能看到

    需求:  调用系统照相机进行拍照,并且保存到系统相册,调用系统相册的时候能看到   系统相册的路径:String cameraPath= Environment.getExternalStorageD ...

  10. vs2017 Remote Debugger远程调试目录

    默认目录:C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\Remote Debugger