CALayer

如果一个layer是被一个view创建的,那么这个view通常会自动被赋值给这个layer的delegate属性(也就算说这个view就是这个layer的代理)。你不应该改变这种关系。对于你自己创建的layer,你可以赋值一个代理对象用来动态提供layer的内容和执行其他的任务。

如果一个layer已经关联了一个view对象。那么layer的delegate属性必须设置为这个拥有这个layer的view本身。

UIView和CALayer的关系

UIView是iOS页面控件的基类,因为UIView直接继承自UIResponder,所以可以响应用户事件,在iOS中创建的每一个UIView都有一个属性layer(CALayer),layer继承自己NSObject,不能响应用户事件,但layer提供了UIView内容的绘制功能,也就是说UIView侧重于对显示内容的管理,CALayer侧重于对内容的绘制。UIView和CALayer相互依赖,UIView依赖于CALayer提供的内容,CALayer依赖UIView提供的容器来显示绘制的内容,UIView可以理解为是CALayer的高级封装。

一、基础使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 边框颜色
self.iconView.layer.borderColor = [UIColor orangeColor].CGColor;
// 边框宽度
self.iconView.layer.borderWidth = 10;
// 圆角半径
self.iconView.layer.cornerRadius = 10;
// 超出图层边框的内容裁剪掉
self.iconView.layer.masksToBounds = YES;
// 颜色
self.iconView.layer.shadowColor = [UIColor blackColor].CGColor;
// 偏移量
self.iconView.layer.shadowOffset = CGSizeMake(10, 10);
// 透明度
self.iconView.layer.shadowOpacity = 0.5;
// 内容
self.iconView.layer.contents = (id)[UIImage imageNamed:@"girl.png"].CGImage;

示例:实现UIImageView既能设置圆角,也能设置阴影? 思路:创建两个图层,一个负责圆角,一个负责阴影

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 创建背景图层用来设置阴影
CALayer *bgLayer = [CALayer layer];
bgLayer.frame = CGRectMake(100, 100, 100, 100);
bgLayer.backgroundColor = [UIColor clearColor].CGColor;
// 设置阴影
bgLayer.shadowColor = [UIColor purpleColor].CGColor;
bgLayer.shadowOffset = CGSizeMake(10, 10);
bgLayer.shadowOpacity = 0.5;
// 创建子图层负责显示图片和设置圆角
CALayer *subLayer = [CALayer layer];
subLayer.frame = bgLayer.bounds;
subLayer.cornerRadius = 20;
subLayer.masksToBounds = YES;
subLayer.contents = (id) [UIImage imageNamed:@"girl.png"].CGImage;
[bgLayer addSublayer:subLayer];
[self.view.layer addSublayer:bgLayer];

二、CALayer的transform属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 平移
self.iconView.layer.transform = CATransform3DMakeTranslation(100, 100, 13210);
//缩放
self.iconView.layer.transform = CATransform3DMakeScale(0.5, 1, 100);
// 旋转
self.iconView.layer.transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);
self.iconView.transform = CGAffineTransformMakeRotation(M_PI_4);
// 旋转 100弧度
[self.iconView.layer setValue:@(100) forKeyPath:@"transform.rotation.z"];
// 全局缩放
[self.iconView.layer setValue:@(2) forKeyPath:@"transform.scale"];
// 指定X轴方向缩放
[self.iconView.layer setValue:@(2) forKeyPath:@"transform.scale.x"];

注意:CALayer 还有一个锚点属性.anchorPoint,锚点默认是在图层的中心位置,如果改变锚点,会对图层position属性造成影响。

三、CALayer的隐式动画

1
2
3
4
5
6
7
8
9
10
11
//直接修改layer的大小、位置等一些属性会默认执行动画(subLayer为自定义创建的layer,添加在self.view.layer上)
self.subLayer.position = CGPointMake(200, 200);
self.subLayer.bounds = CGRectMake(0, 0, 250, 250);
// 开启事务
[CATransaction begin];
// 禁止执行隐式动画
[CATransaction setDisableActions:YES];
self.subLayer.position = CGPointMake(200, 200);
// 提交事务
[CATransaction commit];

我们自己写的动画都属于显式动画,当定义显示动画后,相应的隐式动画会自动取消。

四、CALayer可以动画的属性

由于CALayer在iOS中任务主要是内容展示和动画操作,并且动画操作是CALayer的一个重要功能,因此CALayer很多属性的值在变化的时都有动画效果,这个就是我们之前提到的“隐式动画”(手动创建的CALayer对象,都存在着隐式动画),但UIView的根图层是一个例外,根图层属性修改的时候不形成动画效果,因为根图层充当容器的作用,如果它的属性变化形成动画效果会直接干扰子图层。另外,根图层是是由UIView管理,不能重新创建。

常用的图层属性请参照苹果开发文档中的CALayer Animatable Properties

注意:CALayer使用bounds和position属性,position在子图层的位置由anchorPoint决定,frame属性很少使用
CALayer透明度使用opacity,而不是alpha

五、CALayer的内容绘制

1、使用图片为图层提供内容(适用于图层内容几乎不改变的情况)

1
self.iconView.layer.contents = (id)[UIImage imageNamed:@"girl.png"].CGImage;

2、使用代理提供图层内容
如果图层内容是动态改变的,则可以使用代理对象在需要的时候提供图层并更新内容。图层显示的时候,从代理方法获取内容,代理方法主要有以下两个:

- (void)displayLayer:(CALayer *)layer;
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;

如果实现了displayLayer:方法,实现方法负责创建位图并赋值给contents属性
如果实现了drawLayer: inContext:方法,Core Animation创建一个位图,创业一个用于绘制位图的上下文,并调用代理方法填充该位图,代理方法所需要做的是将内容画在图形上下文中。
注意:代理对象必须实现以上两个方法之一,如果代理对象把以上两个法都实现了,那么图层需要内容的时候,只调用displayLayer:代理方法。

打赏支持一下呗!