在学习iOS的动画之前,我们首先需要了解视图UIView能够显示样式的原理。其实,在屏幕上展示出来的视图样式,其实是由UIView对象中的layer属性所控制的。
CALayer简介
视图UIView类中有一个重要的属性–layer,类型是CALayer类,这个属性是负责视图外观样式的
UIView是UIResponder的子类,展示样式,接受用户的交互。样式部分实际上是由layer属性所控制的。
当我们在开发过程中,假如仅仅希望在界面上定制一块矩形区域的样式而不需要与用户进行交互时,我们完全可以创建一个CALayer的对象,这样做的效率要比创建一个UIView对象要高。
@interface UIView : UIResponder <NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem, UITraitEnvironment, UICoordinateSpace, UIFocusItem, CALayerDelegate>
@property(nonatomic,readonly,strong) CALayer *layer;
常用属性
当我们设置UIView的一些外观属性时,例如:背景颜色、大小、透明度等等,其本质上是修改的UIView对象中layer的属性,只不过苹果官方为了简化代码,从而进行了一些封装操作。因此,我们熟知的一些UIView的外观属性,其实在CALayer类中都有定义。
实例化方法
+(instancetype)layer;
frame:该layer相对于父layer的位置以及大小
@property CGRect frame;
bounds:该layer控制的矩形区域的大小
@property CGRect bounds;
transform:形变属性,可以用于改变layer的大小、位置、角度等
@property CATransform3D transform;
整体样式相关的属性
@property(nullable) CGColorRef backgroundColor;//背景颜色
@property(nullable, strong) id contents;//layer的内容,通常为一张图片
@property CGColorRef borderColor;//边框颜色(CGColorRef类型)
@property CGFloat borderWidth;//边框宽度
layer层次关系控制的方法与属性
@property(nullable, copy) NSArray<CALayer *> *sublayers; //获得一个父layer中所有的子layer
- (void)addSublayer:(CALayer *)layer; //添加一个子layer到父layer上
向layer对象添加一个动画对象
- (void)addAnimation:(CAAnimation *)anim forKey:(nullable NSString *)key;
使用
- (void)viewDidLoad {
[super viewDidLoad];
CALayer *subLayer=[[CALayer alloc]init];
subLayer.backgroundColor=[UIColor yellowColor].CGColor;
subLayer.frame=CGRectMake(100, 200, 200, 200);
subLayer.borderWidth=4.0;
subLayer.borderColor=[UIColor redColor].CGColor;
[self.view.layer addSublayer:subLayer];
}
坐标系
iOS开发中有两大类型的坐标系,分别为点坐标系(point-based coordinate systems)以及单元坐标系(unit coordinate systems)。另外,当我们对视图进行旋转操作时,还会涉及到iOS中的立体坐标系。
当我们设置一个视图的frame或者bounds属性时,使用的是点坐标系,即屏幕的左上角为点坐标系的原点。
当我们学习iOS动画相关的知识之前,还需要了解单元坐标系(unit coordinate systems)。与点坐标系不同,单元坐标系的x轴和y轴的取值都是0~1,其中心位置的坐标是(0.5,0.5)。
position与anchorPoint
之所以需要提前介绍iOS中的坐标系,主要是因为在CALayer类中的两个关键属性–位置(positon)与锚点(anchorPoint),分别使用了点坐标系以及单元坐标系。
- 位置(positon)。在一个CALayer对象中,位置position是点坐标系中的一个点,该点与锚点anchorPoint是同一个点,或者可以理解为与锚点重合。
@property CGPoint position;
- 锚点(anchorPoint),是单元坐标系中的一个点,默认情况下,它是单元坐标系中的中心点,坐标为(0.5,0.5)。锚点可以形象的理解为一个大头针,把大头针插在一个便签的中心位置,然后再定在墙(点坐标系)上的一个固定位置(position),这样便签的位置就确定了。
@property CGPoint anchorPoint;
如下图左侧的两个坐标所示(右侧的是MAC开发的坐标系,与iOS不同),由于位置position与锚点anchorPoint是重合的,所以,通过这两个点就可以确定一个CALayer对象在屏幕上显示的具体位置。锚点的位置默认情况是CALayer对象的中心点,当锚点变成(0,0)时,为了保证CALayer对象的显示位置不变,那必须要修改位置(position)的值。
之所以设置锚点,是因为CALayer对象或视图对象,可以围绕锚点进行旋转。锚点是一个固定的点,所以,改变锚点的位置会影响旋转的效果。默认情况下,是围绕中心点来旋转的,假如我们希望围绕左上角旋转,那就需要修改锚点的值。
立体坐标系
iOS开发中还存在三维立体坐标系,除了我们熟知的x轴和y轴之外,还有z轴,z轴以屏幕的左上角为0点,向屏幕外延伸。在CALayer类中,也可以定义与z轴相关的位置属性.
@property CGFloat zPosition;
@property CGFloat anchorPointZ;
另外,当我们对视图进行旋转操作时,可以围绕x轴、y轴和z轴进行旋转,旋转的效果会不同。
当需要对视图旋转时,我们可以使用CATransform3DMakeRotation()函数对CALayer或UIView的transform属性进行修改。该函数中,我们可以指定所围绕的轴。
CA_EXTERN CATransform3D CATransform3DMakeRotation (CGFloat angle, CGFloat x,
CGFloat y, CGFloat z)
例如,通过围绕不同的坐标轴旋转视图,我们可以得到不同的效果。
围绕z轴旋转:
subLayer.transform = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);
- 围绕y轴旋转
subLayer.transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
- 围绕x轴旋转
subLayer.transform = CATransform3DMakeRotation(M_PI_4, 1, 0, 0);
动画属性
UIView的动画属性本质上是因为CALayer的存在才能去显示动画的。
动画属性
CALayer中的动画属性在开发过程中,我们比较常用的有如下几个。
@property CGRect bounds;//大小
@property(nullable) CGColorRef backgroundColor;//背景颜色
@property CATransform3D transform;//形变
@property(getter=isHidden) BOOL hidden;//隐藏
@property CGFloat borderWidth;//边框的宽度
@property(nullable) CGColorRef borderColor;//边框的颜色
@property float opacity;//透明度
示例
当我们需要改变CALayer的动画属性时,可以调用如下方法,达到播放动画的效果。
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion;
例如:修改subLayer对象的形变属性,使其旋转,在旋转过程中可以播放旋转动画。
[UIView animateWithDuration:2.0 animations:^{
subLayer.transform = CATransform3DMakeRotation(M_PI_4, 1, 1, 1);
}];