iOS核心动画(CoreAnimation)


CoreAnimation是iOS中的核心动画框架,是iOS开发中专门用来处理动画的API,在开发中使用CoreAnimation可以做出很多很炫酷的动画。下面,就对CoreAnimation的使用做出详细的解析。

UIView动画

​ 在说CoreAnimation之前,可以先简单的介绍一下UIView动画,UIView动画用起来很简单,实现的动画也是非常简单。
​ 在开发中,我们也会经常调用到,主要有两种调用方式:

  • block代码块调用

1
2
3
[UIView animateWithDuration:1 animations:^{
self.firstView.frame = CGRectMake(200, 200, 50, 100);
}];

​ 常用的还有delay参数和completion的回调方法,completion中是动画完成后的回调,可以在做一些动画完成后要执行的任务,delay是动画延迟执行的时间。

  • [begin commit]代码段调用

1
2
3
4
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
self.firstView.frame = CGRectMake(200, 200, 50, 100);
[UIView commitAnimations];

​ 这种方式需要将执行的动画内容放到beginAnimations和commitAnimations中间,包括一些要设置的属性,如:Duration、Delay、StartDate、Curve、RepeatCount等等,还可以通过设置setAnimationDelegate代理,来监听动画的开始和结束。

核心动画(CoreAnimation)

​ CoreAnimation的动画实现是在layer层,每一个UIView的对象在创建的时候都会生成一个layer层,我们平时看到的view上展示的元素都是layer层绘制和显示的,通过改变layer的属性,就可以实现复杂的动画了。其实,UIView动画也可以看做是CoreAnimation的封装,不过,值得注意的是:UIView动画在执行完成后,view本身是发生改变的,CoreAnimation在执行完成后,view本身是没有发生改变的,只是看起来变了而已。
​ CoreAnimation的基类为CAAnimation,实现了CAMediaTiming协议,以用来控制动画的时间、速度和时间曲线等,CoreAnimation不能直接使用,需要使用它的子类:CAAnimationGroup、CAPropertyAnimation和CATransition,CAPropertyAnimation一般也不会直接时候,它又有两个子类:CABasicAnimation、CAKeyframeAnimation。

综上所述,可以使用的动画的类包括:

CABasicAnimation: 基础动画
CAKeyframeAnimation: 关键帧动画
CATransition: 转场动画
CAAnimationGroup: 动画组

CABasicAnimation(基础动画)

1
2
3
4
5
CABasicAnimation *basicAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
basicAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(150, 125)];
basicAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 500)];
basicAnimation.duration = 1.0f;
[self.firstView.layer addAnimation:basicAnimation forKey:@"positonAnimation"];

其中,keyPath对应的是想要改变的layer的属性,支持动画的属性主要包括以下这些:

//CATransform3D Key Paths :
rotation.x
rotation.y
rotation.z
rotation 旋转

scale.x
scale.y
scale.z
scale 缩放

translation.x
translation.y
translation.z
translation 平移

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
>CGPoint Key Paths : 
x
y
>
//CGRect Key Paths :
origin.x
origin.y
origin
size.width
size.height
size

>opacity
backgroundColor
cornerRadius
borderWidth
contents
>

//Shadow Key Path:
shadowColor
shadowOffset
shadowOpacity
shadowRadius

经常用到的还有以下属性:

  • fillMode、removedOnCompletion,他们两个同时使用,

basicAnimation.fillMode = kCAFillModeForwards;
basicAnimation.removedOnCompletion = NO;

动画执行完成后,视图不会再回到原来的位置。

  • timingFunction :动画执行时的效果:

basicAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];

同时,要想移除动画,系统提供了两个方法:

1
2
- (void)removeAnimationForKey:(NSString *)key;//移除指定的动画
- (void)removeAllAnimations;//移除某个layer上所有的动画

CAKeyframeAnimation(关键帧动画)

关键帧动画可以为动画的执行过程设置若干个中间点,中间点前后动画的属性可以设置多个不同的值,动画可以沿着设置的中间点顺序执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
CAKeyframeAnimation * keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
keyFrameAnimation.duration = 3.0;
keyFrameAnimation.removedOnCompletion = NO;
keyFrameAnimation.fillMode = kCAFillModeForwards;
keyFrameAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

NSValue * value0 = [NSValue valueWithCGPoint:CGPointMake(150, 125)];
NSValue *value1=[NSValue valueWithCGPoint:CGPointMake(250, 125)];
NSValue *value2=[NSValue valueWithCGPoint:CGPointMake(250, 225)];
NSValue *value3=[NSValue valueWithCGPoint:CGPointMake(100, 400)];
keyFrameAnimation.values = @[value0, value1, value2, value3];

[self.firstView.layer addAnimation:keyFrameAnimation forKey:@"KeyframeAnimationForPosition"];

关键帧动画有几个非常重要的属性:

values:关键帧数组对象,里面每一个元素即为一个关键帧,动画会在对应的时间段内,依次执行数组中每一个关键帧的动画。
path:动画路径对象,可以指定一个路径,在执行动画时路径会沿着路径移动,Path在动画中只会影响视图的Position。
keyTimes:设置关键帧对应的时间点,范围:0-1。如果没有设置该属性,则每一帧的时间平分。

利用path属性,我们可以使用关键帧动画来实现画圆圈的动画:

1
2
3
4
5
6
7
8
CGSize screenSize = [UIScreen mainScreen].bounds.size;
CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
keyFrameAnimation.removedOnCompletion = NO;
keyFrameAnimation.fillMode = kCAFillModeForwards;
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(screenSize.width/2-100, screenSize.height/2-100, 200, 200)];
keyFrameAnimation.path = path.CGPath;
keyFrameAnimation.duration = 2.0f;
[self.firstView.layer addAnimation:keyFrameAnimation forKey:@"KeyframeAnimationCirclePath"];

CATransition(转场动画)

1
2
3
4
5
6
CATransition * transAnimation = [CATransition animation];
transAnimation.type = kCATransitionFade;
transAnimation.subtype = kCATransitionFromLeft;
transAnimation.duration = 1.5;
self.firstView.backgroundColor = [UIColor blueColor];
[self.firstView.layer addAnimation:transAnimation forKey:@"transitionAnimation"];

转场动画两个重要的属性:

type:转场动画的种类,公有api主要有四个:

渐变 kCATransitionFade 、覆盖 kCATransitionMoveIn

推出 kCATransitionPush 、揭开kCATransitionReveal

还有一些私有api:”cube”、”suckEffect”、”oglFlip”、 “rippleEffect”、”pageCurl”、”pageUnCurl”

动画的方向,有以下几种:

kCATransitionFromRight 从右边、kCATransitionFromLeft 从左边

kCATransitionFromTop 从顶部、kCATransitionFromBottom 从底部

CAAnimationGroup(动画组)

CAAnimationGroup顾名思义就是一组动画,动画组中可以添加多个动画,动画组中的动画可以并发运行。我们平时见到的一些炫酷的动画,都是依赖动画组完成的。
CAAnimationGroup最重要的属性:

animations: 数组类型,用来接收动画组中要添加的动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CGSize screenSize = [UIScreen mainScreen].bounds.size;
//关键帧动画(移动)
CAKeyframeAnimation *animation1 = [CAKeyframeAnimation animationWithKeyPath:@"position"];
NSValue *value0 = [NSValue valueWithCGPoint:CGPointMake(0, screenSize.height/2-50)];
NSValue *value1 = [NSValue valueWithCGPoint:CGPointMake(screenSize.width/3, screenSize.height/2-50)];
NSValue *value2 = [NSValue valueWithCGPoint:CGPointMake(screenSize.width/3, screenSize.height/2+50)];
NSValue *value3 = [NSValue valueWithCGPoint:CGPointMake(screenSize.width*2/3, screenSize.height/2-50)];
animation1.values = [NSArray arrayWithObjects:value0,value1,value2,value3,nil];

//缩放动画
CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation2.fromValue = [NSNumber numberWithFloat:0.8f];
animation2.toValue = [NSNumber numberWithFloat:2.0f];

//旋转动画
CABasicAnimation *animation3 = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
animation3.toValue = [NSNumber numberWithFloat:M_PI*4];

//组动画
CAAnimationGroup *groupAnimation = [CAAnimationGroup animation];
groupAnimation.animations = [NSArray arrayWithObjects:animation1,animation2,animation3, nil];
groupAnimation.duration = 3.0f;
[self.firstView.layer addAnimation:groupAnimation forKey:@"groupAnimation"];

总结:

平时大家看到的动画,无论多么复杂,都是由一个个简单的动画组合而成的,在使用的时候,我们要进行合适的组合,控制好动画的属性,就能达到我们满意的效果。