宽泛的说,大多数 CALayer 的属性都是用GPU来绘制
如果对一个 contents 属性设置一张图片,然后裁剪它 - 它就会被纹理的三角形绘制出来, 而不需要软件层面做任何绘制。
解压图片 - PNG或者JPEG压缩之后的图片文件会比同质量的位图小得多。但 是在图片绘制到屏幕上之前,必须把它扩展成完整的未解压的尺寸(通常等同 于图片宽 x 长 x 4个字节)。为了节省内存,iOS通常直到真正绘制的时候才去 解码图片(14章“图片IO”会更详细讨论)。根据你加载图片的方式,第一次对 图层内容赋值的时候(直接或者间接使用 UIImageView )或者把它绘制到 Core Graphics中,都需要对它解压,这样的话,对于一个较大的图片,都会 占用一定的时间
CALayer.shouldRasterize 光栅化属性(把多个图层转化为一个图层-位图),但这会把原本离屏渲染的操作转嫁到 CPU 上去。对于只需要圆角的某些场合,也可以用一张已经绘制好的圆角图片覆盖到原本视图上面来模拟相同的视觉效果。最彻底的解决办法,就是把需要显示的图形在后台线程绘制为图片,避免使用圆角、阴影、遮罩等属性。
光栅化没有问题,使用恰当会提高性能,使用不当会降低性能;
当我们开启光栅化后,需要注意三点问题。
如果我们更新已光栅化的layer,会造成大量的offscreen渲染。
因此CALayer的光栅化选项的开启与否需要我们仔细衡量使用场景。只能用在图像内容不变的前提下的:
① 用于避免静态内容的复杂特效的重绘,例如前面讲到的UIBlurEffect
② 用于避免多个View嵌套的复杂View的重绘。
CALayer 只需要一些与自己相关 的内存:只有它的寄宿图会消耗一定的内存空间。即使直接赋给 contents 属性一 张图片,也不需要增加额外的照片存储大小。如果相同的一张图片被多个图层作
为 contents 属性,那么他们将会共用同一块内存,而不是复制内存块。
但是一旦你实现了 协议中的 -drawLayer:inContext: 方 法或者 UIView 中的 方法(其实就是前者的包装方法),图层就创 建了一个绘制上下文,这个上下文需要的大小的内存可从这个算式得出:图层宽图 层高4字节,宽高的单位均为像素。对于一个在Retina iPad上的全屏图层来说,这 个内存量就是 204815264字节,相当于12MB内存,图层每次重绘的时候都需要 重新抹掉内存然后重新分配。
UIImage imageNamed:
会在加载图片之后立刻进行解压, 而不是等到显示的时候;
[UIImage imageNamed:] 方法仅仅适用于在应用程序资源束目录下的图片, 但是大多数应用的许多图片都要从网络或者是用户的相机中获取,所
以 [UIImage imageNamed:] 就没法用了。
这里,取出image后,又重绘了一遍,书里说这是为当前屏幕做了优化,可能比原图更流畅,我就当他说的话是真的吧;
PNG和JPEG压缩算法作用于两种不同的图片类型:JPEG对于噪点大的图片效 果很好;但是PNG更适合于扁平颜色,锋利的线条或者一些渐变色的图片。为了让 测评的基准更加公平,我们用一些不同的图片来做实验:一张照片和一张彩虹色的 渐变。
离屏渲染
当图层属性的混合体被指定为在未预合成之前不能直接在屏幕中绘制时,屏幕外 渲染就被唤起了。屏幕外渲染并不意味着软件绘制,但是它意味着图层必须在被显 示之前在一个屏幕外上下文中被渲染(不论CPU还是GPU)。图层的以下属性将会 触发屏幕外绘制:
圆角(当和 maskToBounds 一起使用时)
图层蒙板
阴影
GPU会放弃绘制那些完全被其他图层遮挡的像素,但是要计算出一个图层是否被 遮挡也是相当复杂并且会消耗处理器资源。同样,合并不同图层的透明重叠像素 (即混合)消耗的资源也是相当客观的。所以为了加速处理进程,不到必须时刻不 要使用透明图层。任何情况下,你应该这样做:
给视图的 属性设置一个固定的,不透明的颜色
设置 属性为YES
这样做减少了混合行为(因为编译器知道在图层之后的东西都不会对最终的像素 颜色产生影响)并且计算得到了加速,避免了过度绘制行为因为Core Animation可 以舍弃所有被完全遮盖住的图层,而不用每个像素都去计算一遍。
如果是文本的话,一个白色背景的 UILabel (或者其他颜色)会比透明背景要 更高效。
最后,明智地使用 shouldRasterize 属性,可以将一个固定的图层体系折叠成 单张图片,这样就不需要每一帧重新合成了,也就不会有因为子图层之间的混合和 过度绘制的性能问题了。
- CATransformLayer用来创建3D的layer结构,而不是CALayer那样的扁平结构。和普通layer不同的地方有:
1、transform layer只渲染sublayers,那些从CALayer继承下来的属性不起作用,包括:backgroundColor, contents, border style properties, stroke style properties等。(因为他只显示子layer不显示自己)
2、2D图片的处理属性也不起作用,包括:filters, backgroundFilters, compositingFilter, mask, masksToBounds以及阴影属性。
3、opacity属性会应用到每个sublayer,transform layer并不作为一个整体来实现半透明效果。
4、在transform layer上不可以调用hitTest:方法,因为它并不存在一个2D的坐标空间来定位所测试的点。
在transform layer上设置sublayerTransform的m34值,定位一个透视点,sublayer上应用z轴位置变换的动画,就可以看到3D效果。效果如图:
- 关于CALayer的shouldRasterize(光栅化)
开启shouldRasterize后,CALayer会被光栅化为bitmap,layer的阴影等效果也会被保存到bitmap中。
当我们开启光栅化后,需要注意三点问题。
● 如果我们更新已光栅化的layer,会造成大量的offscreen渲染。
因此CALayer的光栅化选项的开启与否需要我们仔细衡量使用场景。只能用在图像内容不变的前提下的:
① 用于避免静态内容的复杂特效的重绘,例如前面讲到的UIBlurEffect
② 用于避免多个View嵌套的复杂View的重绘。
而对于经常变动的内容,这个时候不要开启,否则会造成性能的浪费。
例如我们日程经常打交道的TableViewCell,因为TableViewCell的重绘是很频繁的(因为Cell的复用),如果Cell的内容不断变化,则Cell需要不断重绘,如果此时设置了cell.layer可光栅化。则会造成大量的offscreen渲染,降低图形性能。
当然,合理利用的话,是能够得到不少性能的提高的,因为使用shouldRasterize后layer会缓存为Bitmap位图,对一些添加了shawdow等效果的耗费资源较多的静态内容进行缓存,能够得到性能的提升。
● 不要过度使用,系统限制了缓存的大小为2.5X Screen Size.
如果过度使用,超出缓存之后,同样会造成大量的offscreen渲染。
● 被光栅化的图片如果超过100ms没有被使用,则会被移除
因此我们应该只对连续不断使用的图片进行缓存。对于不常使用的图片缓存是没有意义,且耗费资源的。