iOS动画
本篇文章主要讲解iOS中动画的使用。
1、Core Animation,核心动画。
核心动画执行过程都是在后台操作的,不会阻塞主线程。Core Animation是直接作用在CALayer上的,并非UIView。
CAAnimation 是所有 Core Animation 动画类的父类,CAAnimation是一个抽象类,不能直接使用,应该使用它的子类。CAAnimation常用的子类有以下三个:
CAPropertyAnimation,属性动画
CATransition,转场动画
CAAnimationGroup,组动画
其中,CAPropertyAnimation也是一个抽象类,我们一般使用它的两个子类:
CABasicAnimation,基础动画,
CAKeyframeAnimation,帧动画
另外有一个协议:CAMediaTiming。
CABasicAnimation,基础动画。通过上面的介绍,我们可以知道,核心动画是作用在CALayer层,因此,基础动画是通过改变对象的layer的某个属性来实现动画效果的。至于CALayer的属性有哪些,大家可以自行看API,我这里仅就 position 属性来演示动画效果。下面看代码:
1 - (IBAction)CABasicAnimation:(UIButton *)sender {
2 //参数需要是layer的属性,或者是属性的属性的名字
3 CABasicAnimation *basic = [CABasicAnimation animationWithKeyPath:@"position.x"];
4 basic.fromValue = @100;
5 basic.toValue = @250;
6 basic.duration = 3;
7 basic.repeatCount = 1;
8 //需要手动改变位置,(如果需要改变position的真实位置)
9 // self.redView.layer.position = CGPointMake(250, 100);
10 //key,标识
11 [self.redView.layer addAnimation:basic forKey:nil];
12 }
position.x 来实现的;Line4中制定了x的起始位置,Line5中指定了x的终止位置,Line6设置动画执行时间为3S,Line7设置动画重复次数为1,Line11中,将这个动画指定给 self.redView.layer 。
当上面的动画执行完成后,我们会发现,self.redView又回到了初始位置,也就是说,动画并不会真正改变layer的属性值。我们可以通过Line9中的代码,来实际改变layer的属性值,让对象停留在终止位置。
1.2、CAKeyframeAnimation,关键帧动画。这个和基础动画很类似,只不过是可以通过添加一组基础动画来执行,下面直接上代码,代码解释参考上面的:
1 //关键帧动画
2 - (IBAction)keyFrameAnimation:(UIButton *)sender {
3
4 CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
5 CGPoint point0 = CGPointMake(100, 100);
6 CGPoint point1 = CGPointMake(100, 200);
7 CGPoint point2 = CGPointMake(200, 200);
8 CGPoint point3 = CGPointMake(200, 300);
9 CGPoint point4 = CGPointMake(150, 300);
10 CGPoint point5 = CGPointMake(175, 250);
11 CGPoint point6 = CGPointMake(175, 100);
12
13 NSValue *value1 = [NSValue valueWithCGPoint:point0];
14 NSValue *value2 = [NSValue valueWithCGPoint:point1];
15 NSValue *value3 = [NSValue valueWithCGPoint:point2];
16 NSValue *value4 = [NSValue valueWithCGPoint:point3];
17 NSValue *value5 = [NSValue valueWithCGPoint:point4];
18 NSValue *value6 = [NSValue valueWithCGPoint:point5];
19 NSValue *value7 = [NSValue valueWithCGPoint:point6];
20
21 //根据一组点来创建动画
22 keyFrameAnimation.values = @[value1, value2, value3, value4, value5, value6, value7, value1];
23 keyFrameAnimation.duration = 10;
24 [self.redView.layer addAnimation:keyFrameAnimation forKey:nil];
25 }
上面的代码,大家可以自行创建一个View,即代码中的 self.redView,演示一下就明白了。
1.3 CATransition转场动画。下面看代码:
- (IBAction)transitionAnimation:(UIButton *)sender {
CATransition *transition = [CATransition animation];
transition.type = @"rippleEffect"; //动画过渡类型
transition.subtype = kCATransitionFromLeft; //动画过度方向
transition.repeatCount = HUGE_VALL; //动画重复次数,最大次数
transition.duration = 2; //动画持续时间
[self.redView.layer addAnimation:transition forKey:nil];
}
下面我罗列了一些过渡类型,供大家参考使用:
1 pageCurl 向上翻一页
2 pageUnCurl 向下翻一页
3 rippleEffect 滴水效果
4 suckEffect 收缩效果,如一块布被抽走
5 cube 立方体效果
6 oglFlip 上下翻转效果
1.4 CAAnimationGroup。组动画实际上就是可以将上面的几种动画类型随意组合添加到一个对象上。下面看代码:
1 - (IBAction)groupAnimation:(UIButton *)sender {
2 //创建一个缩放动画
3 CABasicAnimation *basic = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
4 basic.fromValue = @1;
5 basic.toValue = @0.75;
6 //创建一个关键帧动画,从一个位置到另一个位置
7 CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
8 CGPoint point1 = CGPointMake(100, 100);
9 CGPoint point2 = CGPointMake(300, 300);
10 NSValue *value1 = [NSValue valueWithCGPoint:point1];
11 NSValue *value2 = [NSValue valueWithCGPoint:point2];
12 keyFrameAnimation.values = @[value1, value2];
13 //创建一个动画组
14 CAAnimationGroup *group = [CAAnimationGroup animation];
15 group.duration = 4;
16 group.repeatCount = 3;
17 //将上面的两种动画添加到动画组中,动画将同步执行
18 [group setAnimations:@[basic,keyFrameAnimation]];
19 //下面的代码会最终改变对象的位置,否则对象在动画完成后会回到初始位置
20 self.redView.layer.position = CGPointMake(300, 300);
21 //添加动画组
22 [self.redView.layer addAnimation:group forKey:nil];
23 }
1.5 CASpringAnimation,弹簧动画,继承于CABasicAnimation。都不难,上代码吧:
- (IBAction)springAnimation:(UIButton *)sender {
CASpringAnimation *spring = [CASpringAnimation animationWithKeyPath:@"transform.rotation"];
//质量越大,惯性越大
spring.mass = 1;
//阻尼系数,越大停止的越快
spring.damping = 0.2;
spring.fromValue = @0.2;//transform.rotation的初始值
spring.toValue = @0.75;//transform.rotation的结束值
spring.repeatCount = 1;
spring.autoreverses = YES;//自动回弹
//初始速度
spring.initialVelocity = 5;
spring.duration = spring.settlingDuration;
[self.redView.layer addAnimation:spring forKey:@"spring"];
}
下面我总结了一下keypath值,大家可以参考:
transform.scale = 比例轉換
transform.scale.x = 闊的比例轉換
transform.scale.y = 高的比例轉換
transform.rotation.z = 平面圖的旋轉
opacity = 透明度
margin
zPosition
backgroundColor 背景颜色
cornerRadius 圆角
borderWidth
bounds
contents
contentsRect
cornerRadius
frame
hidden
mask
masksToBounds
opacity
position
shadowColor
shadowOffset
shadowOpacity
shadowRadius
上面就是核心动画的全部内容了,基本就是以代码来讲解,这些东西原理上没什么可说的,主要是知道怎么用。下面说说UIView动画。
[UIView beginAnimations:nil context:nil] 和 [UIView commitAnimations] 之间。
一般来说,能够影响控件外形的属性都可以使用动画,而UIView动画的实现由两种方式,我们先看第一种方式,下面看代码,一个改变控件Frame的动画:
1 - (IBAction)changeFrame:(UIButton *)sender {
2 //第一个参数,动画标示
3 [UIView beginAnimations:@"changeFrame" context:nil];
4 //设置动画次数
5 [UIView setAnimationRepeatCount:100];
6 //设置动画时长
7 [UIView setAnimationDuration:1];
8 //设置动画速率
9 [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
10 CGRect frame = self.showView.frame;
11 frame.origin.y = 200;
12 //改变frame,y值
13 self.showView.frame = frame;
14 //开始动画
15 [UIView commitAnimations];
16 }
大家看注释应该能明白这段代码的意思。
再上一段代码,缩放动画:
1 //缩放动画
2 - (IBAction)scaleButtonAction:(UIButton *)sender {
3
4 [UIView beginAnimations:@"UIView" context:nil];
5 self.showView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.5, 1.5);
6 }
旋转动画:
1 // 旋转
2 - (IBAction)rotateButtonAction:(UIButton *)sender {
3 [UIView beginAnimations:nil context:nil];
4 // 第一个参数: 以谁为基准进行旋转
5 // 第二个参数: 旋转的弧度
6 // CGAffineTransformIdentity 原始形变
7 [UIView setAnimationDuration:1];
8 self.showView.transform = CGAffineTransformRotate(self.showView.transform, -M_PI / 180 * 30);
9 [UIView commitAnimations];
10 }
我们再来看一下另一种方式实现的UIView动画。
简单的Block动画:
1 // 简单block动画
2 - (IBAction)simpleBlock:(UIButton *)sender{
3 [UIView animateWithDuration:2 animations:^{
4 CGPoint point = self.planeImageView.center;
5 point.y += 100;
6 self.planeImageView.center = point;
7 } completion:^(BOOL finished) {
8 NSLog(@"动画结束");
9 [UIView animateWithDuration:2 animations:^{
10 CGPoint point = self.planeImageView.center;
11 point.y -= 100;
12 self.planeImageView.center = point;
13 } completion:nil];
14
15 }];
16 }
复杂的Block动画:
1 // 复杂的block
2 - (IBAction)complexBlock:(UIButton *)sender {
3 [UIView animateWithDuration:2 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
4 self.planeImageView.transform = CGAffineTransformRotate(self.planeImageView.transform, M_PI / 180 * 90);
5 } completion:^(BOOL finished) {
6 // 还原到初始形变
7 // self.planeImageView.transform = CGAffineTransformIdentity;
8 }];
9 }
转场动画:
1 // 过度动画, 转场动画
2 - (IBAction)transitionAnimation:(UIButton *)sender {
3 [UIView beginAnimations:nil context:nil];
4 [UIView setAnimationDuration:2];
5 // 第一个参数: 转场动画的类型
6 // 第二个参数: 给哪个对象添加转场动画
7 // 第三个参数: 缓存设置(YES执行效率更高)
8 [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.label cache:YES];
9 self.label.text = @"熊大熊二的故事";
10 [UIView commitAnimations];
11 }
弹簧动画:
1 // 弹簧动画
2 - (IBAction)sprintAnimation:(UIButton *)sender {
3 // 1. 动画时长
4 // 2. 延迟时间
5 // 3. 阻尼系数, 越大, 弹簧形变越小
6 // 4. 速度
7 // 5. 动画类型选项
8 [UIView animateWithDuration:2 delay:0 usingSpringWithDamping:0.1 initialSpringVelocity:10 options:UIViewAnimationOptionCurveLinear animations:^{
9 CGPoint point = self.planeImageView.center;
10 point.y += 260;
11 self.planeImageView.center = point;
12
13 } completion:^(BOOL finished) {
14 NSLog(@"动画结束");
15 }];
16 }
大家可以发现,第二种实现方式实际上是对第一种方式使用了Block封装,相对来说,第二种实现方式更加的方便。而仔细看核心动画和UIView动画,我们也可以发现,实际上,UIView动画就是对核心动画的封装,使用起来更加的方便。