最近总结一下CoreAnimation的基本知识。。。( CALayer Animatable Properties)
Core Animation,中文翻译为核心动画,它是一组非常强大的动画处理API,使用它能做出非常炫丽的动画效果,而且往往是事半功倍。也就是说,使用少量的代码就可以实现非常强大的功能。
Core Animation可以用在Mac OS X和iOS平台。
Core Animation的动画执行过程都是在后台操作的,不会阻塞主线程。
要注意的是,Core Animation是直接作用在CALayer上的,并非UIView。
先上一张图,看一下核心动画中的基本类和他们之间的关系,箭头表示继承关系。
下面分一下几点介绍
- 1.CAAnimation
- 2.CAPropertyAnimation
- 3.CABasicAnimation 基本动画
- 4.CAKeyframeAnimation 关键帧动画
- 5.CATransition 转场动画
- 6.CAAnimationGroup 动画组
1、CAAnimation
CAAnimation 是核心动画中的基础抽象类,其他的都是继承自他来使用。
CAAnimation
provides the basic support for the [CAMediaTiming] and [CAAction]protocols.
You do not create instance of
[CAAnimation]: to animate Core Animation layers or SceneKit objects,
create instances of the concrete subclasses [CABasicAnimation],
[CAKeyframeAnimation], [CAAnimationGroup], or [CATransition]
CAAnimation遵循< CAMediaTiming >和< CAAction >协议,不能直接使用CAAnimation去实现动画效果,而是使用它的子类CABasicAnimation 、CAKeyframeAnimation、CAAnimationGroup、CATransition。
CAMediaTiming
可以调整动画的持续时间、重复次数、动画的速度等。
CAAction
通过响应动作的方法来实现动画
看一下CAAnimation里面的API
+ (nullable id)defaultValueForKey:(NSString *)key;
类方法:根据相对的属性key返回属性值,有点类似字典
- (BOOL)shouldArchiveValueForKey:(NSString *)key;
根据相对的属性key该属性的值返回是否可以归档。
属性(部分属性是遵循CAMediaTiming协议中的)
属性 | 说明 |
---|---|
duration | 动画持续的时间,默认是0 |
speed | 速度比例,默认是1,如果调节为n,那么在动画持续时间内会加速执行n次 |
beginTime | 开始时间 ,默认是0, 若想延迟ns,就设置为CACurrentMediaTime()+n,CACurrentMediaTime()为图层的当前时间 |
timeOffset | 时间偏移,用来暂停动画使用 |
repeatCount | 动画重复的次数,默认为0,无限循环可以设置HUGE_VALF或者MAXFLOAT |
repeatDuration | 动画重复的时间间隔,默认0 |
autoreverses | 倒向动画,默认是NO,如果是Yes,动画正向执行后,会倒向执行一次 |
removedOnCompletion | 默认为YES,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示动画执行后的状态,那就设置为NO,不过还要设置fillMode为kCAFillModeForwards |
fillMode | 决定动画开始之前或者结束之后的形态 |
timingFunction | 速度控制函数,控制动画运行的节奏,可以使用该类中的类方法: + (instancetype)functionWithName:(NSString *)name; name传入上面的类型创建一个CAMediaTimingFunction对象 |
fillMode属性
kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态,即动画停止的状态,不过要配合removedOnCompletion属性设置为NO使用才有效果,不然没效果。
kCAFillModeBackwards 在动画开始前,只需要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始。动画结束后,layer会恢复到之前的状态
kCAFillModeBoth 这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态,不过要配合removedOnCompletion属性设置为NO使用才有效果,不然没效果
kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态
timingFunction属性
- kCAMediaTimingFunctionLinear(线性):匀速,给你一个相对静态的感觉
- kCAMediaTimingFunctionEaseIn渐进):动画缓慢进入,然后加速离开
- kCAMediaTimingFunctionEaseOut(渐出):动画全速进入,然后减速的到达目的地
- kCAMediaTimingFunctionEaseInEaseOut(渐进渐出):动画缓慢的进入,中间加速,然后减速的到达目的地。这个是默认的动画行为。
- kCAMediaTimingFunctionDefault:默认的(线性):匀速
CAAnimation的代理方法
@interface NSObject (CAAnimationDelegate)
/* Called when the animation begins its active duration. */
// 动画开始时调用
- (void)animationDidStart:(CAAnimation *)anim;
/* Called when the animation either completes its active duration or
* is removed from the object it is attached to (i.e. the layer). 'flag'
* is true if the animation reached the end of its active duration
* without being removed. */
// 动画结束后调用
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
@end
2.CAPropertyAnimation
CAPropertyAnimation继承自CAAnimation,也是一个抽象类,是CABasicAnimation和CAKeyframeAnimation的父类,不能直接使用来生成动画效果。
keyPath
通过指定CALayer的一个属性名称为keyPath(NSString类型),并且对CALayer的这个属性的值进行修改,达到相应的动画效果。
/* Creates a new animation object with its `keyPath' property set to
* 'path'. */
+ (instancetype)animationWithKeyPath:(nullable NSString *)path;
/* The key-path describing the property to be animated. */
@property(nullable, copy) NSString *keyPath;
keyPath类型 | 动画效果 |
---|---|
transform.rotation.z | Z轴旋转 |
transform.rotation.x | X轴旋转 |
transform.rotation.y | Y轴旋转 |
transform.scale.x | 宽的比例转换 |
transform.scale.y | 高的比例转换 |
opacity | 透明度 |
backgroundColor | 背景色 |
anchorPoint | 定位点,锚点,默认中心点(0.5, 0.5) |
borderColor | 边框颜色 |
borderWidth | 边框宽度 |
bounds | 大小 |
contents | 内容 |
contentsRect | 内容矩形 |
cornerRadius | 圆角 |
frame | 位置 |
hidden | 隐藏 |
mask | 标记 |
maskToBounds | 切割 |
position | 位置 |
shadowOffset | 阴影偏移 |
shadowColor | 阴影颜色 |
shadowRadius | 阴影角度 |
shadowOpacity | 阴影透明度 |
strokeEnd | 颜色从无到有 |
strokeStart | 颜色从有到无 |
3.CABasicAnimation 基本动画
继承自CAPropertyAnimation,基本动画。主要的效果是keyPath里面的,指定keyPath相应属性的初始值和keyPath相应属性的结束值。然后执行动画。
keyPath类型 | 动画效果 |
---|---|
fromValue | keyPath相应属性的初始值 |
toValue | keyPath相应属性的结束值 |
动画过程说明:
随着动画的进行,在长度为duration的持续时间内,keyPath相应属性的值从fromValue渐渐地变为toValue。
keyPath内容是CALayer的可动画Animatable属性。
如果fillMode = kCAFillModeForwards同时removedOnComletion = NO,那么在动画执行完毕后,图层会保持显示动画执行后的状态。但在实质上,图层的属性值还是动画执行前的初始值,并没有真正被改变。
fillMode = kCAFillModeForwards同时removedOnComletion = NO要同时设定才有效
-(void)createCAAnimation
{
//核心动画是作用在CALayer层的,所以先创建一个layer来承载动画
CALayer *layer = [[CALayer alloc] init];
layer.bounds = CGRectMake(0, 0, 100, 100);
//layer没有center的属性,而是position
layer.position = self.view.center;
layer.backgroundColor = [[UIColor blackColor]colorWithAlphaComponent:0.5].CGColor;
[self.view.layer addSublayer:layer];
//创建一个CAAnimation
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
//属性
//动画持续的时间,默认是0 , animation.duration = 5;
//速度比例,默认是1,如果调节为n,那么在动画持续时间内会加速执行n次
animation.speed = 1;
//开始时间 ,默认是0,若想延迟ns,就设置为CACurrentMediaTime()+n,CACurrentMediaTime()为图层的当前时间
animation.beginTime = 0;
//时间偏移,用来暂停动画使用
animation.timeOffset = 0;
//动画重复的次数,默认为0,无限循环可以设置HUGE_VALF或者MAXFLOAT
animation.repeatCount = 0;
//动画重复的时间间隔,默认0
animation.repeatDuration = 0;
//倒向动画,默认是NO,如果是Yes,动画正向执行后,会倒向执行一次
animation.autoreverses = NO;
//默认为YES,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示动画执行后的状态,那就设置为NO,不过还要设置fillMode为kCAFillModeForwards
animation.removedOnCompletion = YES;
//决定动画开始之前或者结束之后的形态
animation.fillMode = kCAFillModeRemoved;
//速度控制函数,控制动画运行的节奏
CAMediaTimingFunction *timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
animation.timingFunction = timingFunction;
//开始
animation.fromValue = @(M_PI);
//结束
animation.toValue = @(M_PI/4);
//为layer加上动画
[layer addAnimation:animation forKey:@"ANIMATION"];
}
4. CAKeyframeAnimation 关键帧动画
和CABasicAnimation一样继承自CAPropertyAnimation,可以理解为CABasicAnimation的升级版。
- CABasicAnimation只能指定首尾两个keyPath,然后动画从fromValue执行到toValue。
- CAKeyframeAnimation可以指定动画的keypath到一个values数组中,然后依次执行。
属性 | 说明 |
---|---|
values | NSArray对象。里面的元素称为“关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧 |
path | 可以设置一个CGPathRef、CGMutablePathRef,让图层按照路径轨迹移动。path只对CALayer的anchorPoint和position起作用。如果设置了path,那么values将被忽略 |
keyTimes | 可以为对应的关键帧指定对应的时间点,每个动画的时长,总时长为1,然后运动到那个点是,该点在总时长的百分之几,和valus个数相同,keyTimes中的每一个时间值都对应values中的每一帧。如果没有设置keyTimes,各个关键帧的时间是平分的 |
timingFunctions | 每个帧的运动类型,NSArray中存放CAMediaTimingFunction对象,个数要比values中的少一个。因为动画的真实个数要比设置的value少一个。 |
calculationMode | 该属性决定了物体在每个子路径下是跳着走还是匀速走,跟timeFunctions属性有点类似 |
rotationMode |
calculationMode
- kCAAnimationLinear//线性,默认
- kCAAnimationDiscrete//离散,无中间过程,但keyTimes设置的时间依旧生效,物体跳跃地出现在各个关键帧上
- kCAAnimationPaced//平均,keyTimes跟timeFunctions失效
- kCAAnimationCubic//平均,同上
- kCAAnimationCubicPaced//平均,同上
rotationMode
- kCAAnimationRotateAuto
- kCAAnimationRotateAutoReverse
-(void)createValuesAnimation
{
CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
//设置路径
keyframeAnimation.values = [[NSArray alloc] initWithObjects:
[NSValue valueWithCGPoint:CGPointMake(self.view.center.x, self.view.center.y)],
[NSValue valueWithCGPoint:CGPointMake(self.view.frame.size.width-25, self.view.center.y)],
[NSValue valueWithCGPoint:CGPointMake(self.view.frame.size.width-25, self.view.frame.origin.y+89)],
[NSValue valueWithCGPoint:CGPointMake(self.view.frame.origin.x+25, self.view.frame.origin.y+89)],
[NSValue valueWithCGPoint:CGPointMake(self.view.frame.origin.x+25, self.view.center.y)],
[NSValue valueWithCGPoint:CGPointMake(self.view.frame.origin.x+25, self.view.frame.size.height-25)],
[NSValue valueWithCGPoint:CGPointMake(self.view.frame.size.width-25, self.view.frame.size.height-25)],
[NSValue valueWithCGPoint:CGPointMake(self.view.center.x, self.view.center.y)],
nil];
//整个动画的时长
keyframeAnimation.duration = 10;
//每个动画的时长,总时长为1,然后运动到那个点是,该点在总时长的百分之几,和valus个数相同
keyframeAnimation.keyTimes = @[@(0),@(0.2),@(0.4),@(0.5),@(0.55),@(0.7),@(0.9),@(1)];
keyframeAnimation.repeatCount = MAXFLOAT;
[self.layer addAnimation:keyframeAnimation forKey:nil];
[self.view.layer addSublayer:self.layer];
}
-(void)createPathAnimation
{
CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
//创建一个路径
CGMutablePathRef path = CGPathCreateMutable();
//添加圆形
//CGPathAddEllipseInRect(path, NULL, CGRectMake(50, 90, 200, 200));
//矩形
CGPathAddRect(path, NULL, CGRectMake(50, 90, 200, 200));
//设置路径
keyframeAnimation.path = path;
//释放路径
CGPathRelease(path);
//设置动画时间
keyframeAnimation.duration = 3;
//原路线返回
// keyframeAnimation.autoreverses = YES;
keyframeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
//设置重复次数
keyframeAnimation.repeatCount = MAXFLOAT;
//匀速kCAAnimationCubicPaced
keyframeAnimation.calculationMode = kCAAnimationCubicPaced;
[self.layer addAnimation:keyframeAnimation forKey:nil];
[self.view.layer addSublayer:self.layer];
}
5.CATransition 转场动画
继承自CAAnimation,切换页面的动画。
属性 | 说明 |
---|---|
type | 动画类型下面会列出各种类型 |
subtype | 方向 |
startProgress | 从什么地方开始动画,默认动画0到1 |
endProgress | 从什么地方结束动画,默认动画0到1 |
type | 说明 |
---|---|
开放的四种基本效果 | |
kCATransitionPush | 推入效果 |
kCATransitionMoveIn | 移入效果 |
kCATransitionReveal | 截开效果 |
kCATransitionFade | 渐入渐出效果 |
私有的效果 | |
cube | 方块 |
suckEffect | 三角 |
rippleEffect | 水波抖动 |
pageCurl | 上翻页 |
pageUnCurl | 下翻页 |
oglFlip | 上下翻转 |
cameraIrisHollowOpen | 镜头快门开 |
cameraIrisHollowClose | 镜头快门关 |
subtype的类型
- kCATransitionFromRight 从右边开始
- kCATransitionFromLeft 从左边来时
- kCATransitionFromTop 从上面开始
- kCATransitionFromBottom 从下面开始
- (void)push
{
//创建一个转场动画
CATransition *stansition = [CATransition animation];
//设置动画时间
stansition.duration = 1;
//设置类型
stansition.type = @"cube";
stansition.subtype = kCATransitionFromRight;
//添加动画
[self.navigationController.view.layer addAnimation:stansition forKey:nil];
NextViewController *nextVC = [[NextViewController alloc] init];
[self.navigationController pushViewController:nextVC animated:YES];
}
6.CAAnimationGroup 动画组
多个动画的组合,即可以把多个动画放在animations数组中,然后同时执行多个动画。
-(void)createAnimationGroup
{
//创建一个动画组
CAAnimationGroup *animationGroup = [[CAAnimationGroup alloc] init];
//动画时间,如果动画组中的时间没有设置是不行的,如果设置了动画组的时间,然后里面的动画没有设置时间, 那么则以动画组的时间为准,如果里面的具体动画也设置了时间,那么以具体的动画设置的时间为准
animationGroup.duration = 10;
//创建一个基础动画
CABasicAnimation *basicAnimaiton = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
basicAnimaiton.toValue = @(M_PI);
//创建一个帧动画
CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
//设置路径
keyframeAnimation.values = [[NSArray alloc] initWithObjects:
[NSValue valueWithCGPoint:CGPointMake(self.view.center.x, self.view.center.y)],
[NSValue valueWithCGPoint:CGPointMake(self.view.frame.size.width-25, self.view.center.y)],
[NSValue valueWithCGPoint:CGPointMake(self.view.frame.size.width-25, self.view.frame.origin.y+89)],
[NSValue valueWithCGPoint:CGPointMake(self.view.frame.origin.x+25, self.view.frame.origin.y+89)],
[NSValue valueWithCGPoint:CGPointMake(self.view.frame.origin.x+25, self.view.center.y)],
[NSValue valueWithCGPoint:CGPointMake(self.view.frame.origin.x+25, self.view.frame.size.height-25)],
[NSValue valueWithCGPoint:CGPointMake(self.view.frame.size.width-25, self.view.frame.size.height-25)],
[NSValue valueWithCGPoint:CGPointMake(self.view.center.x, self.view.center.y)],
nil];
//每个动画的时长,总时长为1,然后运动到那个点是,该点在总时长的百分之几,和valus个数相同
keyframeAnimation.keyTimes = @[@(0),@(0.2),@(0.4),@(0.5),@(0.55),@(0.7),@(0.9),@(1)];
//将两个动画添加到动画组中
animationGroup.animations = @[basicAnimaiton,keyframeAnimation];
[self.layer addAnimation:animationGroup forKey:nil];
[self.view.layer addSublayer:self.layer];
}