原文翻译:Designing for iOS: Graphics & Performance
在幕后发生的事情
为了更好的理解性能是如何被影响的,我们需要进一步的观察在graphics后的结构。
在最上层,UIKit这个高级别的OC framework 来管理用户界面的视图。它由一些列的类组成,每一类都配合了一个特别的UI control ,例如UIButton 和UILabel。UIKit是建立在Core Animation上的,Core Animation 是在OS X Leopard系统时引进的并且移植到了iOS系统上,它的使用使得过度效果变得非常的顺滑。
在结构的更底部有个叫OpenGL ES的东西,一个开源框架,他用来在手机上渲染2D/3D动画。OpenGL ES
被广泛用于游戏绘画和支持Core Animation 和UIKit。最后一块在软件区的是Core Graphics –其曾被称为Quartz,它是一个基于CPU的画图引擎,并且首次是在OS X系统上亮相的。这两个低级别的 frameworks 都是用C语言写的。最底层的是硬件,包括显卡(GPU)和主处理器(CPU)。
当GPU用来组成并且渲染绘图时,OpenGL 和Core Animation /UIKit 的实现是在这个基础之上的,我们叫他硬件加速。直到现在硬件加速是iOS对Android 的一个巨大优势;后者的很多动画有很多可察觉的波动是由于绘画是依赖于CPU造成的。
离屏渲染
离屏渲染牵涉到在将绘图送到GPU进行屏幕渲染前,会先在后台用CPU产生bitmap绘画。在iOS中离屏绘画发生在以下几个情况下:
1. Core Graphics (任何有CG前缀的类)
2. drawRect()方法,即使是空的实现
3. CALayer 设置了shouldRasterize 属性是YES
4. CALayer 用mask 和动态shadows (setMasksToBounds)(setShadow*)
5. 任意在屏幕上展现的text,包括Core Text
6. 组透明度(UIViewGroupOpacity)
Note :iOS 9.0 之后UIButton设置圆角会触发离屏渲染,而UIImageView里png图片设置圆角不会触发离屏渲染了,如果设置其他阴影效果之类的还是会触发离屏渲染的。
离屏渲染检测方式
一般性的法则,当牵涉到动画时,离屏渲染会影响到性能。你可以用instruments监测哪些UI部件正在进行离屏渲染:
1. 将iOS 设备插入电脑。。。。。。。把冰箱们打开
2. 打开Instrument。。。。。。把大象放进冰箱
3.选择 iOS > Graphics > Core Animation template
。。。。
4.选择你的设备
5.点击“Color Offscreen-Rendered Yellow”
6.在你的设备上任何离屏渲染都会有黄色覆盖
你也可以用模拟器步骤是:Debug > Color Offscreen-Rendered更简单些。
UIButton优化情况
利用提前渲染的部件
用一个UIImage作为背景的自定义button ,在image存在磁盘的情况下完全依赖于GPU。一个可以改变size的背景图片是一个减少内存消耗的好办法,因为它可以减小bundle的大小,在拉伸和平铺像素时会利用硬件加速。
使用CALayers
当我们使用masking去渲染圆角时会导致离屏渲染。我们还需要关闭隐式动画。重点,除非你需要动画过渡,否则CoreAnimation 时无法满足自定义绘图的。
DrawRect
drawRect方法依赖于Core Graphics 去做自定义的绘图,但是它最大的缺点是它处理触摸事件的方式:每次当button被按下,setNeedsDisplay
强迫按钮重绘,并不是一次,而是每次点击会有两次重回。这并不时一个好的方式去运用CPU和内存,特别是在界面上有特别多的按钮。– drawRect 在有点击事件的视图应注意应用。
混合方法
所以,是不是只有提前渲染才是可行的解决方案。简短回答:No。如果你仍然需要灵活的绘画,是有办法优化你的代码并减少执行台面空间的。一个方式就是产生一个可拉伸的bitmap并且在所有实例上都重用它。
我们将从创建一个UIButton的子类开始,我们将定定义我们类的静态变量。
下面是这个他封装的三方库,解决button的性能问题,有兴趣可以自己研究下。click here
其他优秀文章:绘制像素到屏幕上