前言
在iOS的世界,圆角无处不在,而且必须存在。因为圆角是符合人类视觉安全体验的,圆角让人觉得舒适,而方角在潜意识层次是具有伤害体验的,因为尖尖的东西总是有可能对人造成伤害的,所以我们更喜欢圆角。在我之前的文章中讲过,在iOS的中设置圆角是非常容易的一件事情,这也体现出苹果也是非常重视圆角这件事情的。

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

实测
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帧每秒。

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

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。)


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

转载:小心别让圆角成了你列表的帧数杀手相关推荐

  1. python将文件数据转换成二维列表

    贴一个做数据清洗时写的代码, 做数据处理时,原文件数据在进行处理时需要转换成一定格式, 原始文件数据:123.txt 1,3,4 2,3,5 1,2,3,5 2,5 利用Python转换成二维列表: ...

  2. python 如何将字符串数字列表转换成数字列表,如何将数字列表转换成字符串数字列表?map(eval,list(str))

    字符串数字列表转换成数字列表 # -*- encoding: utf-8 -*- """ @File : test.py @Time : 2019/10/28 23:37 ...

  3. Java黑皮书课后题第6章:**6.25(将毫秒转化成小时、分钟、秒数)使用下面的方法头,编写一个将毫秒数转换成小时数、分钟数和描述的方法,返回形式如“小时:分钟:秒“

    6.25(将毫秒转化成小时.分钟.秒数)使用下面的方法头,编写一个将毫秒数转换成小时数.分钟数和描述的方法,返回形式如"小时:分钟:秒" 题目 题目描述 破题 代码 运行实例 题目 ...

  4. python 摄像头录制帧率_实践:用python实现把视频以帧数输出成连续的多图片

    在处理图像的时候,如果获取了一个视频,想把视频以帧数输出成连续的多图片构成图像数据集. 有人就想问什么软件可以把一段电影视频的每一帧连续自动保存成图片? 其实用很短的python程序就能快速实现该功能 ...

  5. 学成在线 课程列表 页面

    学成在线 课程列表 页面 在美好的礼拜天,正好我们不调休,把最后一个页面给完成了. 和其他用浮动座位布局方式比起来,课程类表页面最终还是使用了flexbox去布局,一来主要内容最下面的 分页 部分用浮 ...

  6. 实时帧数手机_【转载保存】别着急扔掉旧手机:简单改造即变PC游戏帧数监测神器...

    闲逛时看到的硬核好文,先保留. PC玩家中,不少人都会有在玩游戏时观测电脑硬件状态的习惯.比如查看游戏帧数.CPU频率.GPU频率或是温度等.大多数人都是通过第三方软件,在游戏内把监测数据显示到电脑显 ...

  7. 用栈来实现将一个十进制数转换成等值的二进制数或者八进制数

    栈的应用 栈的一个典型应用是将10进制数转换成等值的二进制数,或者八进制数,由于将十进制数转换成二进制数或者八进制数的时候符合栈的"后进先出"的特性,因为其算法思路就是不断取余然后 ...

  8. IDEA几个设置:设置空格显示成小点、显示行数、 Ctrl + 鼠标滚轮 快捷键来控制代码字体大小显示、护眼背景色

    1.设置空格显示成小点和显示行数,最初如图所示 1.1 现在进行设置,设置如图. 1.2 设置后有行数显示,空格变成小点显示效果图. 2.Ctrl + 鼠标滚轮 快捷键来控制代码字体大小显示 3.设置 ...

  9. 【转载】vob格式转换成avi格式的影片和制作的方法

    vob格式转换成avi格式的影片和制作的方法: 打开DVD根目录,你可看到两个子目录:VIDEO_TS和AUDIO_TS.AUDIO_TS中并没有内容,DVD的所有内容都存放在VIDEO_TS目录之下 ...

  10. 语言学与计算机交叉学科,科学网—计算机与信息科学交叉研究领域:X-informatics (转载2篇) - 章成志的博文...

    在"第二届中美计算机科学峰会"(博主注: 2008年7月底)上,伊立诺伊大学阿贝纳香槟分校的马克·斯厄尔(Marc Snir) 教授作了题为"Computer & ...

最新文章

  1. es6学习笔记8--Map数据结构
  2. ELK/EFK — Overview
  3. win2012每次启动显示服务器管理器,win2012r2服务器管理器打开角色.功能出错
  4. Google Play应用上架流程(含踩坑经验)
  5. box-shadow阴影合集
  6. Mybatis配置文件参数定义
  7. “吸才”的字节跳动和“散才”的好未来
  8. python学习笔记(十六)-Python多线程多进程
  9. link中的rel表示relation(关系),表示了当前文档与 Web 集合中其他文档的关系
  10. mysql多索引结构_MySQL-索引结构详解
  11. H5游戏推苻一HTML5游戏一手,【盘点】五个最热门的H5游戏平台
  12. 拓端tecdat|R语言POT超阈值模型和极值理论EVT分析
  13. php分页查询·······类
  14. matlab 取点画图,Matlab plot画图学习---画点以及两点连线
  15. cmd运行javac解析中文乱码
  16. 统一认证 ldap mysql_ZABBIX 对接 LDAP实现用户登陆统一认证
  17. CentOS7安装Zeppelin完整步骤
  18. 阿里云数据库RDS如何用Navicat连接?
  19. word文档任意位置开始插入页码
  20. 动态规划法(二)——弗洛伊德算法

热门文章

  1. Quartz job Cluster下报错
  2. 使用Oracle数据库进行企业开发(三)
  3. 比特币原理——交易与UTXO
  4. django中collectstatic的使用
  5. CEF3中js调用delphi内部方法
  6. Codeforces Beta Round #14 (Div. 2) D. Two Paths 树的直径
  7. JavaWeb项目开发案例精粹-第3章在线考试系统-005action层
  8. HD 2177(威佐夫博弈 入门)
  9. 【博客之星】帮我投一票吧,谢谢
  10. android api文档中文版_干货分享 | Android 存储空间的最佳实践 (下)