CALayer的寄宿图:图层中包含的图层
contents属性
contents 是一个id类型,但实际上它需要一个CGImage类型才能正常显示,UIImage有一个CGImage属性,返回一个CGImageRef类型,但是这个类型不是一个Cocoa对象,而是一个Core Foundation类型,因此需要进行实现如下转换。
layer.contents = (__bridge id)image.CGImage;
可以通过contents属性,在UIView的宿主图层中显示一张图片
contentGravity
可以通过设置UIView的contentMode属性来设置图层上显示图片的显示属性,但是UIView大多数视觉相关的属性比如contentMode,对这些属性的操作其实是对对应图层的操作。
CALayer上与contentMode对应的属性是contentsGravity,不同的是,它是一个NSString类型,作用也是为来决定内容在图层的边界中怎么对齐
,例如在图层中等比例拉伸以适应图层的边界设置如下:
self.layView.layer.contentsGravity = kCAGravityResizeAspect;
- contentScale:此属性定义了
寄宿图的像素尺寸和视图大小的比例
,默认是1.0的浮点数,属于支持高分辨率屏幕机制的一部分,用来判断在绘制图层的时候应该为寄宿图创建的空间的大小和需要显示的图片的拉伸度(假设没有设置contentsGravity属性)
一旦设置了contentsGravity属性,contentScale设置将会失效,当用代码的方式处理寄宿图时,正确设置:layer.contentsScale = [UIScreen mainScreen].scale;
maskToBounds
CALayer和UIView一样,仍然会绘制超过边界的内容或者子视图,对于决定是否显示超出边界的内容,UIView通过clipsToBounds设置,CALayer通过maskToBounds设置
contentsRect:允许在图层边框里显示寄宿图的一个子域。
contentsRect
不是按点来计算的,而使用来单位坐标,数值在0~1之间,是一个相对值,相对于寄宿图的尺寸,默认的contentsRect是{0,0,1,1}意味着整个寄宿图都是可见的。
事实上给contentsRect设置一个负数的原点或者大于{1,1}的尺寸也是可以的,此时最外面的像素会被拉伸填充剩下的区域。
contentsRect用处之一是:能够使用图片拼合,即将多张图片拼合打包整合到一张大图上一次性载入。相比于多次加载不同的图片,优势在于:内存使用、加载事件、渲染性能等。
contentsCenter:类型是CGRect,定义了图层中可拉伸区域和一个固定的边框,改变这个值并不会影响到寄宿图的显示,除非图层的大小改变了。
默认情况下,contentsCenter是{0,0,1,1},表示layer大小改变了,寄宿图会根据contentsGravity设置的模式均匀的拉伸,下图表示的是contentsCenter设置为{0.25,0.25,0.5,0.5} 的效果。类似于UIImage中的-resizableImageWithCapInsets:方法
Custom Drawing:除了通过将CGImgae赋值给contents来设置寄宿图外,另外一种设置寄宿图的方法就是:直接用Core Graphics绘制寄宿图。通过继承UIView并实现其-drawRect: 方法来实现自定义绘制。
- 视图在屏幕上出现时,其-drawRect:方法会被自动调用
- -drawRect:没有默认的实现,因为对于UIView来说,寄宿图不是必须的,如果UIView检测到-drawRect:方法被调用了,那么它就会为视图分配一个寄宿图,寄宿图的像素尺寸等于视图大小乘以contentScale的值
- 如果不需要寄宿图,就不要创建这个方法,因为会造成CPU资源的浪费和内存的浪费,所以苹果建议
如果没有自定义绘制的任务就不要在子类中写一个空的-drawRect:方法
。 - -drawRect:方法里面的代码利用Core Graphics去绘制一个寄宿图,然后内容被缓存起来直到它需要被更新,一般是开发者调用了-setNeedsDisplay方法
- 虽然-drawRect:是UIView的方法,但是实际上都是底层的CALayer安排了重绘工作和保存了绘制的图片。
CALayerDelegate:CALayer有一个可选的delegate属性,实现了CALayerDelegate协议,当CALayer需要一个内容特定的信息时,就会从协议中请求。
- 当寄宿图需要被重绘时,CALayer会请求它的代理给它一个寄宿图来显示,调用下面这个代码方法实现:
(void)displayLayer:(CALayer *)layer
- 如果代理没有实现
-displayLayer:
方法,CALayer就会尝试调用下面的这个方法:
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)cox;
在调用这个方法之前,CALayer创建了一个合适尺寸的空寄宿图(尺寸由bounds和contentsScale决定的)以及一个Core Graphics的绘制上下文环境,为绘制寄宿图做准备,并且作为ctx参数传入
需要说明的是:
1、CALayer与UIView不同,它不会自动重绘它的内容,可以通过显示调用 -display:方法实现
2、使用CALayerDelegate协议绘制寄宿图时,超出图层边界的会被裁剪,因为它没有对超出边界外的内容提供绘制支持