iOS动画:CoreAnimation
我们经常会添加动画,其实大部分情况是用的Core Animation。
一. 简介
Core Animation是iOS和macOS平台上负责图形渲染与动画的基础框架。Core Animation可以作用与动画视图或者其他可视元素,为你完成了动画所需的大部分绘帧工作。你只需要配置少量的动画参数(如开始点的位置和结束点的位置)即可使用Core Animation的动画效果。Core Animation将大部分实际的绘图任务交给了图形硬件来处理,图形硬件会加速图形渲染的速度。这种自动化的图形加速技术让动画拥有更高的帧率并且显示效果更加平滑,不会加重CPU的负担而影响程序的运行速度。

给view加上动画,本质上是对其layer进行操作,layer包含了各种支持动画的属性,动画则包含了属性变化的值、变化的速度、变化的时间等等,两者结合产生动画的过程。
一个动画的本质,就是动画对象(这里是 UIView
)的状态,基于时间变化的反应。
简单说,就是给定任意一个时刻,如果你都能得到这个动画对象的位置和、形状等等属性,你就能实现这个动画了。
属性值的变化,既可能是位置、透明度、旋转角度等的变化,也包括形状的改变,比如从一条直线变化成一个圆圈,目标就是要得到变化过程中特定时刻的中间态。
二. 基本概念
我们可以将 iOS 的动画分为两大类:
- 系统提供的 关键帧动画 实现方式;用户指定 关键 信息,系统实现动画过程,对用户而言操作起来会简单些。
- 逐帧动画 实现方式;用户自己 画 出每一帧画面,系统操作方法简单,但用户操作的工作量就会大一些。

-
CAAnimation
是所有动画对象的父类,实现了CAMediaTiming协议,负责控制动画的时间、速度和时间曲线等等,是一个抽象类,不能直接使用。 -
CAMediaTiming
,动画所有跟时间相关的属性(duration, beginTime, repeatCount等)都来自于CAMediaTiming协议,它由CALayer和CAAnimation及其子类实现。协议一共定义了8个属性,通过这8个属性就能完全地控制动画时间。 -
CAPropertyAnimation
,CAAnimation的子类,也是一个抽象类,自身并不能对layer进行动画操作,需要其子类CABasicAnimation和CAKeyframeAnimation来实现动画操作。 -
CABasicAnimation
,基础动画,可设定起始结束两个关键帧的信息。主要提供了对于CALayer对象中的可变属性进行简单动画的操作。比如:位移、透明度、缩放、旋转、背景色等等。 -
CAKeyframeAnimation
,关键帧动画,除首尾外,还可添加多个中间关键点。CABaseAnimation只能从一个数值(fromValue)变换成另一个数值(toValue),而CAKeyframeAnimation则会使用一个NSArray保存一组关键帧。CABasicAnimation可看做是最多只有2个关键帧的CAKeyframeAnimation。 -
CAAnimationGroup
,组动画,组合多个动画,因为上面两种动画一次只能设置一个属性值。将CAAnimationGroup对象加入层后,组中所有动画对象可以同时并发运行。 -
CATransition
,过渡动画,CAAnimation的子类,用于做过渡动画或者转场动画,能够为层提供移出屏幕和移入屏幕的动画效果,默认是淡入。比如修改一个CALayer
的背景色时,是从初始色慢慢淡入过渡到结束色。可修改为新颜色把旧颜色顶出去等效果。还可使用CIFilter
滤镜做过渡效果,一些开源UIViewController
的过渡动画使用了这种方式。
核心动画是作用在CALayer,每一个view都有其对应的layer,这个layer是root layer。
核心动画和UIView动画的对比:UIView动画可以看成是对核心动画的封装,和UIView动画不同的是,通过核心动画改变layer的状态(比如position),动画执行完毕后实际上是没有改变的(表面上看起来已改变)。
显式动画可以定义动画的路径、开始值、结束值、持续时间、重复次数等,生成的实例添加到layer上就开始执行动画。动画在结束后返回layer的原状态,可以在addAnimation之后修改layer的属性来让它保持动画结束的状态,或者变换其他状态。
另外,除了显示动画,还有隐式动画,如给layer的属性赋值,下面这段代码就会产生一个动画效果。
CALayer *layer = [CALayer layer];
layer.backgroundColor = [UIColor yellowColor].CGColor;
layer.frame = CGRectMake(100, 100, 100, 100);
[self.view.layer addSublayer:layer];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
layer.frame = CGRectOffset(layer.frame, 0, 100);
});
一些常用属性:
1.duration : 动画的持续时间
2.autoreverses : 执行的动画按照原动画返回执行
3.timingFunction : 控制动画的显示节奏系统提供五种值选择,分别是:
- kCAMediaTimingFunctionLinear 线性动画
- kCAMediaTimingFunctionEaseIn 先慢后快
- kCAMediaTimingFunctionEaseOut 先快后慢
- kCAMediaTimingFunctionEaseInEaseOut 先慢后快再慢
- kCAMediaTimingFunctionDefault 默认,也属于中间比较快
delegate : 动画代理。能够检测动画的执行和结束。
@interface NSObject (CAAnimationDelegate)
- (void)animationDidStart:(CAAnimation *)anim;
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
@end
path:关键帧动画中的执行路径
type : 过渡动画的动画类型,系统提供了四种过渡动画。
- kCATransitionFade 渐变效果
- kCATransitionMoveIn 进入覆盖效果
- kCATransitionPush 推出效果
- kCATransitionReveal 揭露离开效果
subtype : 过渡动画的动画方向 - kCATransitionFromRight 从右侧进入
- kCATransitionFromLeft 从左侧进入
- kCATransitionFromTop 从顶部进入
- kCATransitionFromBottom 从底部进入
三. 示例
1.CABasicAnimation
// 1. CABasicAnimation(基础动画)
CABasicAnimation *animation1 = [CABasicAnimation animationWithKeyPath:@"position"];
animation1.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 100)];
animation1.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 200)];
animation1.duration = 1.;
// 如果fillMode=kCAFillModeForwards和removedOnComletion=NO,那么在动画执行完毕后,图层会保持显示动画执行后的状态。但在实质上,图层的属性值还是动画执行前的初始值,并没有真正被改变。
// animation1.fillMode = kCAFillModeForwards;
// animation1.removedOnCompletion = NO;
UIView *demo = [UIView new];
demo.backgroundColor = [UIColor redColor];
demo.frame = CGRectMake(100, 100, 100, 100);
[self.view addSubview:demo];
[demo.layer addAnimation:animation1 forKey:@"demoPosition"];
2.CAKeyframeAnimation
/**
2.CAKeyframeAnimation(关键帧动画)
CABaseAnimation只能从一个数值(fromValue)变换成另一个数值(toValue),而CAKeyframeAnimation则会使用一个NSArray保存一组关键帧。
values : 就是上述的NSArray对象。里面的元素称为”关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧
path : 可以设置一个CGPathRef\CGMutablePathRef,让层跟着路径移动。path只对CALayer的anchorPoint和position起作用。如果你设置了path,那么values将被忽略。
keyTimes : 可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧.当keyTimes没有设置的时候,各个关键帧的时间是平分的。
**/
UIView *demo2 = [UIView new];
demo2.backgroundColor = [UIColor greenColor];
demo2.frame = CGRectMake(200, 100, 100, 100);
[self.view addSubview:demo2];
CAKeyframeAnimation *animation2 = [CAKeyframeAnimation animationWithKeyPath:@"position"];
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 200, 100, 200)];
animation2.path = path.CGPath;
animation2.duration = 3.;
[demo2.layer addAnimation:animation2 forKey:@"demo2Position"];
3.CAAnimationGroup
/**
3.CAAnimationGroup(组动画)
CAAnimation的子类,可以保存一组动画对象,将CAAnimationGroup对象加入层后,组中所有动画对象可以同时并发运行。
重要属性
animations : 用来保存一组动画对象的NSArray
**/
UIView *demo3 = [UIView new];
demo3.backgroundColor = [UIColor lightGrayColor];
demo3.frame = CGRectMake(0, 200, 100, 100);
[self.view addSubview:demo3];
CAKeyframeAnimation *ani = [CAKeyframeAnimation animationWithKeyPath:@"position"];
NSValue *va0 = [NSValue valueWithCGPoint:CGPointMake(0, 100)];
NSValue *va1 = [NSValue valueWithCGPoint:CGPointMake(100, 200)];
NSValue *va2 = [NSValue valueWithCGPoint:CGPointMake(250, 320)];
NSValue *va3 = [NSValue valueWithCGPoint:CGPointMake(200, 500)];
ani.values = [NSArray arrayWithObjects:va0,va1,va2,va3, nil];
//缩放动画
CABasicAnimation *ani2 = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
ani2.fromValue = [NSNumber numberWithFloat:0.8f];
ani2.toValue = [NSNumber numberWithFloat:2.0f];
//旋转动画
CABasicAnimation *ani3 = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
ani3.toValue = [NSNumber numberWithFloat:M_PI*4];
// 组动画
CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = [NSArray arrayWithObjects:ani,ani2,ani3, nil];
group.duration = 6;
[demo3.layer addAnimation:group forKey:@"demo3Group"];
参考文献: