第八篇:layer的显式动画

2018-01-19  本文已影响34人  意一ineyee

在上一篇中我们研究了layer的隐式动画,隐式动画是一个很棒的实现layer层基础动画的方式,但是它并不能实现layer层的关键帧动画和过渡动画,所以本篇将学习layer的显式动画,显式动画可分为:属性动画(基础动画和关键帧动画)、动画组过渡动画

第二篇隐式动画我们说到隐式动画可以直接作用于layer的可动画属性,但是不能直接作用于UIView关联的那个layer的可动画属性,因为UIKit框架把UIView关联的layer的隐式动画给禁用了。而显式动画就不一样了,显式动画也是作用于layer层的,但是它既可以作用于直接创建的layer,也可以作用于view关联的layer,所以我们就不必区分了,直接怼layer就可以了。


目录

一、属性动画(CAPropertyAnimation)

1、基础动画(CABasicAnimation)
(1)什么是基础动画?
(2)如何使用基础动画?
(3)举例说明基础动画需要注意的三个地方及解决
2、关键帧动画(CAKeyframeAnimation)
(1)什么是关键帧动画?
(2)如何使用关键帧动画?
(3)举例说明设置关键帧的两个方法:数组关键帧法和路径关键帧法

二、动画组(CAAnimationGroup)

(1)什么是动画组?
(2)如何使用动画组?

三、过渡动画

(1)什么是过渡动画?
(2)如何使用过渡动画?

四、什么情况下使用显示动画


一、属性动画(CAPropertyAnimation)

我们知道想要做属性动画的话,可以直接使用UIView的block属性动画,也可以使用layer的隐式动画来实现,那么这里的layer显示动画的属性动画就是我们实现属性动画的第三种选择。

属性动画又有两个子类,我们平常主要使用这两个子类来做动画,它们是基础动画(CABasicAnimation)关键帧动画(CAKeyframeAnimation),接下来我们将分别介绍:

1、基础动画(CABasicAnimation)
(1)什么是基础动画?

第一篇中UIView block基础动画说过了,类似。

(2)如何使用基础动画?

基础动画的使用也很简单,只需要按以下7个步骤来就可以了:

(3)举个例子

给customLayer背景色的改变加一个动画,给customLayer1切圆角的改变加一个动画

(清单3.1)

//
//  ViewController.m
//  CoreAnimation
//
//  Created by 意一yiyi on 2017/11/13.
//  Copyright © 2017年 意一yiyi. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()<CAAnimationDelegate>

@property (strong, nonatomic) CALayer *customLayer;
@property (strong, nonatomic) CALayer *customLayer1;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.customLayer = [[CALayer alloc] init];
    self.customLayer.frame = CGRectMake(100, 100, 100, 100);
    self.customLayer.backgroundColor = [UIColor redColor].CGColor;
    [self.view.layer addSublayer:self.customLayer];
    
    self.customLayer1 = [[CALayer alloc] init];
    self.customLayer1.frame = CGRectMake(100, 250, 100, 100);
    self.customLayer1.backgroundColor = [UIColor redColor].CGColor;
    [self.view.layer addSublayer:self.customLayer1];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    CABasicAnimation *basicAnimation = [[CABasicAnimation alloc] init];
    NSLog(@"customLayer背景色basicAnimation===%@", basicAnimation);
    basicAnimation.delegate = self;
    basicAnimation.keyPath = @"backgroundColor";
    basicAnimation.toValue = (__bridge id _Nullable)([UIColor orangeColor].CGColor));
    basicAnimation.duration = 3;
    [self.customLayer addAnimation:basicAnimation forKey:nil];
    
    CABasicAnimation *basicAnimation1 = [[CABasicAnimation alloc] init];
    NSLog(@"customLayer1切圆角basicAnimation1===%@", basicAnimation1);
    basicAnimation1.delegate = self;
    basicAnimation1.keyPath = @"cornerRadius";
    basicAnimation1.toValue = @(50);
    basicAnimation1.duration = 3;
    [self.customLayer1 addAnimation:basicAnimation1 forKey:nil];
}

- (void)animationDidStart:(CAAnimation *)anim {
    
    NSLog(@"动画开始了===%@", anim);
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    
    NSLog(@"动画结束了===%@", anim);
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
1.gif

运行,我们可以看到确实有了动画,但是也发现了如下问题:

(清单3.2)

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    
    NSLog(@"动画结束了===%@", anim);
    
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    self.customLayer.backgroundColor = [UIColor orangeColor].CGColor;
    self.customLayer1.cornerRadius = 50;
    [CATransaction commit];
}
1.gif

运行,发现可以了,但是又发现两个问题:

(清单3.3)

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    CABasicAnimation *basicAnimation = [[CABasicAnimation alloc] init];
    NSLog(@"customLayer背景色basicAnimation===%@", basicAnimation);
    basicAnimation.delegate = self;
    basicAnimation.keyPath = @"backgroundColor";
    basicAnimation.toValue = (__bridge id _Nullable)([UIColor orangeColor].CGColor);
    basicAnimation.duration = 3;
    basicAnimation.removedOnCompletion = NO;// 动画结束后不自动移除动画
    basicAnimation.fillMode = kCAFillModeForwards;// 动画结束后保持结束时的那一帧
    [self.customLayer addAnimation:basicAnimation forKey:nil];
    
    CABasicAnimation *basicAnimation1 = [[CABasicAnimation alloc] init];
    NSLog(@"customLayer1切圆角basicAnimation1===%@", basicAnimation1);
    basicAnimation1.delegate = self;
    basicAnimation1.keyPath = @"cornerRadius";
    basicAnimation1.toValue = @(50);
    basicAnimation1.duration = 3;
    basicAnimation1.removedOnCompletion = NO;
    basicAnimation1.fillMode = kCAFillModeForwards;
    [self.customLayer1 addAnimation:basicAnimation1 forKey:nil];
}

(清单3.3)

2018-01-16 11:06:09.205151+0800 CoreAnimation[1582:390479] customLayer背景色basicAnimation===<CABasicAnimation: 0x1c803aa40>
2018-01-16 11:06:09.205444+0800 CoreAnimation[1582:390479] customLayer1切圆角basicAnimation1===<CABasicAnimation: 0x1c803ab20>
2018-01-16 11:06:09.205989+0800 CoreAnimation[1582:390479] 动画开始了===<CABasicAnimation: 0x1c803ab40>
2018-01-16 11:06:09.206101+0800 CoreAnimation[1582:390479] 动画开始了===<CABasicAnimation: 0x1c803ab00>
2018-01-16 11:06:12.207372+0800 CoreAnimation[1582:390479] 动画结束了===<CABasicAnimation: 0x1c803ab40>
2018-01-16 11:06:12.207838+0800 CoreAnimation[1582:390479] 动画结束了===<CABasicAnimation: 0x1c803ab00>

我们惊奇地发现,我们创建的基础动画和动画开始、结束代理方法带回来的动画并不是一个动画。因为动画开始、结束代理方法带回来的动画是我们创建的基础动画的深拷贝,omg,这种方法失败了。

(清单3.4)

//
//  ViewController.m
//  CoreAnimation
//
//  Created by 意一yiyi on 2017/11/13.
//  Copyright © 2017年 意一yiyi. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()<CAAnimationDelegate>

@property (strong, nonatomic) CALayer *customLayer;
@property (strong, nonatomic) CALayer *customLayer1;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.customLayer = [[CALayer alloc] init];
    self.customLayer.frame = CGRectMake(100, 100, 100, 100);
    self.customLayer.backgroundColor = [UIColor redColor].CGColor;
    [self.view.layer addSublayer:self.customLayer];
    
    self.customLayer1 = [[CALayer alloc] init];
    self.customLayer1.frame = CGRectMake(100, 250, 100, 100);
    self.customLayer1.backgroundColor = [UIColor redColor].CGColor;
    [self.view.layer addSublayer:self.customLayer1];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    CABasicAnimation *basicAnimation = [[CABasicAnimation alloc] init];
    NSLog(@"customLayer背景色basicAnimation===%@", basicAnimation);
    basicAnimation.delegate = self;
    basicAnimation.keyPath = @"backgroundColor";
    basicAnimation.toValue = (__bridge id _Nullable)([UIColor orangeColor].CGColor);
    basicAnimation.duration = 3;
    [self.customLayer addAnimation:basicAnimation forKey:@"basicAnimation"];
    
    CABasicAnimation *basicAnimation1 = [[CABasicAnimation alloc] init];
    NSLog(@"customLayer1切圆角basicAnimation1===%@", basicAnimation1);
    basicAnimation1.delegate = self;
    basicAnimation1.keyPath = @"cornerRadius";
    basicAnimation1.toValue = @(50);
    basicAnimation1.duration = 3;
    [self.customLayer1 addAnimation:basicAnimation1 forKey:@"basicAnimation1"];
}

- (void)animationDidStart:(CAAnimation *)anim {
    
    NSLog(@"动画开始了===%@", anim);
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    self.customLayer.backgroundColor = [UIColor orangeColor].CGColor;
    self.customLayer1.cornerRadius = 50;
    [CATransaction commit];
    
    NSLog(@"动画结束了===%@, %@", [self.customLayer animationForKey:@"basicAnimation"], self.customLayer1.animationKeys);
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

但是运行,发现输出都是空,不知道为什么?待解。

(清单3.5)

2018-01-16 13:12:46.985628+0800 CoreAnimation[1695:434274] customLayer背景色basicAnimation===<CABasicAnimation: 0x1c803e280>
2018-01-16 13:12:46.986083+0800 CoreAnimation[1695:434274] customLayer1切圆角basicAnimation1===<CABasicAnimation: 0x1c803e360>
2018-01-16 13:12:46.986961+0800 CoreAnimation[1695:434274] 动画开始了===<CABasicAnimation: 0x1c803e380>
2018-01-16 13:12:46.987066+0800 CoreAnimation[1695:434274] 动画开始了===<CABasicAnimation: 0x1c803e340>
2018-01-16 13:12:49.988287+0800 CoreAnimation[1695:434274] 动画结束了===(null), (null)
2018-01-16 13:12:49.988567+0800 CoreAnimation[1695:434274] 动画结束了===(null), (null)

(清单3.6)

//
//  ViewController.m
//  CoreAnimation
//
//  Created by 意一yiyi on 2017/11/13.
//  Copyright © 2017年 意一yiyi. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()<CAAnimationDelegate>

@property (strong, nonatomic) CALayer *customLayer;
@property (strong, nonatomic) CALayer *customLayer1;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.customLayer = [[CALayer alloc] init];
    self.customLayer.frame = CGRectMake(100, 100, 100, 100);
    self.customLayer.backgroundColor = [UIColor redColor].CGColor;
    [self.view.layer addSublayer:self.customLayer];
    
    self.customLayer1 = [[CALayer alloc] init];
    self.customLayer1.frame = CGRectMake(100, 250, 100, 100);
    self.customLayer1.backgroundColor = [UIColor redColor].CGColor;
    [self.view.layer addSublayer:self.customLayer1];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    CABasicAnimation *basicAnimation = [[CABasicAnimation alloc] init];
    NSLog(@"customLayer背景色basicAnimation===%@", basicAnimation);
    basicAnimation.delegate = self;
    basicAnimation.keyPath = @"backgroundColor";
    basicAnimation.toValue = (__bridge id _Nullable)([UIColor orangeColor].CGColor);
    basicAnimation.duration = 3;
    [basicAnimation setValue:self.customLayer forKey:@"tag"];
    [self.customLayer addAnimation:basicAnimation forKey:nil];
    
    CABasicAnimation *basicAnimation1 = [[CABasicAnimation alloc] init];
    NSLog(@"customLayer1切圆角basicAnimation1===%@", basicAnimation1);
    basicAnimation1.delegate = self;
    basicAnimation1.keyPath = @"cornerRadius";
    basicAnimation1.toValue = @(50);
    basicAnimation1.duration = 3;
    [basicAnimation1 setValue:self.customLayer1 forKey:@"tag"];
    [self.customLayer1 addAnimation:basicAnimation1 forKey:nil];
}

- (void)animationDidStart:(CAAnimation *)anim {
    
    NSLog(@"动画开始了===%@", anim);
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    
    if ([anim valueForKey:@"tag"] == self.customLayer) {
        
        [CATransaction begin];
        [CATransaction setDisableActions:YES];
        self.customLayer.backgroundColor = [UIColor orangeColor].CGColor;
        [CATransaction commit];
    }
    
    if ([anim valueForKey:@"tag"] == self.customLayer1) {
        
        [CATransaction begin];
        [CATransaction setDisableActions:YES];
        self.customLayer1.cornerRadius = 50;
        [CATransaction commit];
    }
    
    NSLog(@"动画结束了===%@, %@", [self.customLayer animationForKey:@"basicAnimation"], self.customLayer1.animationKeys);
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

2、关键帧动画(CAKeyframeAnimation)
(1)什么是关键帧动画?

关键帧动画同样也是属性动画的一个子类,它也是用来做layer层的属性动画的,它可以用来做一些比较复杂的属性动画。比如说,我们看到基础动画的一个弊端就是它只需要给一个初始值和结束值就可以了,这样的效果在情境下就显得生硬甚至不能满足需求。而关键帧动画就可以帮助我们摆脱基础动画仅仅是初始值和结束值的束缚,可以随意设置一连串关键帧,甚至是绘制曲线。

(2)如何使用关键帧动画?

关键帧动画的使用也很简单,只需要按以下7个步骤来就可以了:

(3)举个例子
//
//  ViewController.m
//  CoreAnimation
//
//  Created by 意一yiyi on 2017/11/13.
//  Copyright © 2017年 意一yiyi. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()<CAAnimationDelegate>

@property (strong, nonatomic) CALayer *customLayer;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.customLayer = [[CALayer alloc] init];
    self.customLayer.frame = CGRectMake(100, 100, 100, 100);
    self.customLayer.backgroundColor = [UIColor redColor].CGColor;
    [self.view.layer addSublayer:self.customLayer];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    CAKeyframeAnimation *basicAnimation = [[CAKeyframeAnimation alloc] init];
    basicAnimation.delegate = self;
    basicAnimation.keyPath = @"backgroundColor";
    basicAnimation.values = @[
                              (__bridge id _Nullable)([UIColor redColor].CGColor),// 第一帧我们要主动设置为layer初始状态的属性值
                              (__bridge id _Nullable)([UIColor orangeColor].CGColor),
                              (__bridge id _Nullable)([UIColor yellowColor].CGColor),
                              (__bridge id _Nullable)([UIColor greenColor].CGColor)
                              ];
    basicAnimation.duration = 3;
    [basicAnimation setValue:self.customLayer forKey:@"tag"];
    [self.customLayer addAnimation:basicAnimation forKey:nil];
}

- (void)animationDidStart:(CAAnimation *)anim {
    
    NSLog(@"动画开始了");
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    self.customLayer.backgroundColor = [UIColor greenColor].CGColor;
    [CATransaction commit];
    
    NSLog(@"动画结束了");
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
1.gif

我们知道UIView block关键帧动画只能设置数组关键帧,所以如果有的场景下,我们需要连续的关键帧就需要使用显式动画的关键帧动画了,它支持路径关键帧。

(清单3.8)

//
//  ViewController.m
//  CoreAnimation
//
//  Created by 意一yiyi on 2017/11/13.
//  Copyright © 2017年 意一yiyi. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()<CAAnimationDelegate>

@property (strong, nonatomic) UIImageView *customImageView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.customImageView = [[UIImageView alloc] init];
    self.customImageView.frame = CGRectMake(100, 100, 100, 100);
    self.customImageView.backgroundColor = [UIColor clearColor];
    self.customImageView.image = [UIImage imageNamed:@"汽车"];
    [self.view addSubview:self.customImageView];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    CAKeyframeAnimation *keyframeAnimation = [[CAKeyframeAnimation alloc] init];
    keyframeAnimation.delegate = self;
    keyframeAnimation.keyPath = @"position";
    
    // 绘制一个三次贝塞尔曲线
    UIBezierPath *bezierPath = [[UIBezierPath alloc] init];
    [bezierPath moveToPoint:CGPointMake(150, 150)];
    [bezierPath addCurveToPoint:CGPointMake(150, 450) controlPoint1:CGPointMake(250, 250) controlPoint2:CGPointMake(50, 350)];
    // 绘制一个shapeLayer放在屏幕上显得更形象
    CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
    shapeLayer.path = bezierPath.CGPath;
    shapeLayer.fillColor = [UIColor clearColor].CGColor;
    shapeLayer.strokeColor = [UIColor magentaColor].CGColor;
    shapeLayer.lineWidth = 3.0f;
    [self.view.layer addSublayer:shapeLayer];
    
    keyframeAnimation.path = bezierPath.CGPath;
    keyframeAnimation.duration = 3;
    keyframeAnimation.rotationMode = kCAAnimationRotateAuto;// 让layer根据曲线的切线自动旋转方向
    [keyframeAnimation setValue:self.customImageView forKey:@"tag"];
    [self.customImageView.layer addAnimation:keyframeAnimation forKey:nil];
}

- (void)animationDidStart:(CAAnimation *)anim {
    
    NSLog(@"动画开始了");
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    self.customImageView.layer.position = CGPointMake(150, 450);
    [CATransaction commit];
    
    NSLog(@"动画结束了");
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
1.gif

二、动画组

(1)什么是动画组?

动画组其实很简单了,它是另外一个继承于CAAnimation的子类,它提供了一个animations的数组属性用来把很多个熟悉感动画组合起来一起执行和控制,避免一堆动画单个控制的繁琐

当然了,我们不用组合动画而是把单个单个的动画分别添在同一个layer上也是可以的。

(2)如何使用动画组?

很简单了,创造单个单个的动画,然后把这些单个单个的动画赋值给动画组的animations数组,然后把这个动画组添加到layer上,这一堆动画就会开始同时执行了。

举例:把上面的基础动画和关键帧动画组合起来,构成动画组。
(清单3.9)

//
//  ViewController.m
//  CoreAnimation
//
//  Created by 意一yiyi on 2017/11/13.
//  Copyright © 2017年 意一yiyi. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()<CAAnimationDelegate>

@property (strong, nonatomic) CALayer *customLayer;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.customLayer = [[CALayer alloc] init];
    self.customLayer.frame = CGRectMake(100, 100, 100, 100);
    self.customLayer.backgroundColor = [UIColor redColor].CGColor;
    self.customLayer.contents = (__bridge id _Nullable)([UIImage imageNamed:@"汽车"].CGImage);
    self.customLayer.contentsScale = [UIScreen mainScreen].scale;
    [self.view.layer addSublayer:self.customLayer];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    // 基础动画
    CABasicAnimation *basicAnimation = [[CABasicAnimation alloc] init];
    basicAnimation.keyPath = @"backgroundColor";
    basicAnimation.toValue = (__bridge id _Nullable)([UIColor orangeColor].CGColor);
    
    // 关键帧动画
    CAKeyframeAnimation *keyframeAnimation = [[CAKeyframeAnimation alloc] init];
    keyframeAnimation.keyPath = @"position";
    // 绘制一个三次贝塞尔曲线
    UIBezierPath *bezierPath = [[UIBezierPath alloc] init];
    [bezierPath moveToPoint:CGPointMake(150, 150)];
    [bezierPath addCurveToPoint:CGPointMake(150, 450) controlPoint1:CGPointMake(250, 250) controlPoint2:CGPointMake(50, 350)];
    // 绘制一个shapeLayer放在屏幕上显得更形象
    CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
    shapeLayer.path = bezierPath.CGPath;
    shapeLayer.fillColor = [UIColor clearColor].CGColor;
    shapeLayer.strokeColor = [UIColor magentaColor].CGColor;
    shapeLayer.lineWidth = 3.0f;
    [self.view.layer addSublayer:shapeLayer];
    keyframeAnimation.path = bezierPath.CGPath;
    keyframeAnimation.rotationMode = kCAAnimationRotateAuto;// 让layer根据曲线的切线自动旋转方向
    
    // 动画组
    CAAnimationGroup *animationGroup = [[CAAnimationGroup alloc] init];
    animationGroup.delegate = self;
    animationGroup.animations = @[basicAnimation, keyframeAnimation];
    animationGroup.duration = 3;
    [self.customLayer addAnimation:animationGroup forKey:nil];
}

- (void)animationDidStart:(CAAnimation *)anim {
    
    NSLog(@"动画开始了");
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    self.customLayer.backgroundColor = [UIColor orangeColor].CGColor;
    self.customLayer.position = CGPointMake(150, 450);
    [CATransaction commit];
    
    NSLog(@"动画结束了");
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
1.gif

三、过渡动画

(1)什么是过渡动画?

第一篇说过了,类似。

过渡动画(CATransition)同样是CAAnimation的一个子类,但它不像属性动画那样是平滑地在两个属性值之间做动画,而是直接对整个图层做变化(即过渡动画不是针对图层的属性的,而是针对图层的,当然它可以用来做属性动画而不局限于做属性动画,我们甚至可以在不改变图层或者不知道改变了图层什么东西的情况下直接给图层添加一个过渡动画,也就是说过渡动画是给图层添的动画,只要有layer存在,我们任何时机任何情况都能给layer添加过渡动画,可以给layer添,也可以给view关联的layer添),即首先展示修改前的图层外观,然后通过一个过渡动画的效果变换到新的外观展示

(2)如何使用过渡动画?

过渡动画类型(type):用来控制过渡动画的效果,有下面九种:

fade// 淡入淡出的效果(没有方向)
push// 新图层从一侧推入、旧图层从一侧推出来展示新外观效果
moveIn// 新图层从一侧推入来展示新外观效果、但旧图层没有从一侧推出
reveal// 旧图层从一侧推出来展示新外观效果、但新图层没有从一侧推入
oglFlip// 正面和背面的二维翻转效果
cube// 立方体翻转效果
pageCurl// 翻页效果
suckEffect// 收缩效果
rippleEffect// 水滴波纹效果(没有方向)

过渡动画子类型如下(subType):用来控制过渡动画的方向,有下面四种,type里除了fade和rippleEffect没有方向之外,其它效果都有方向

kCATransitionFromTop// 从底部开始过渡动画
kCATransitionFromLeft// 从左侧开始过渡动画
kCATransitionFromBottom// 从顶部开始过渡动画
kCATransitionFromRight// 从右侧开始过渡动画

转场动画缓冲曲线控制(timingFunction):有下面四种

kCAMediaTimingFunctionEaseInEaseOut// 动画慢进,逐渐加快,逐渐减慢,慢出
kCAMediaTimingFunctionEaseIn// 动画慢进,逐渐加快
kCAMediaTimingFunctionEaseOut// 动画逐渐减慢,慢出
kCAMediaTimingFunctionLinear// 动画匀速

可见layer显式动画的过渡动画效果要比UIView block过渡动画的效果多了好多,因此效果也会更丰富一些。

下面举个例子,类似第一篇的,切换imageView的图片和label的文本,只不过是个水纹效果:

//
//  ViewController.m
//  CoreAnimation
//
//  Created by 意一yiyi on 2017/11/13.
//  Copyright © 2017年 意一yiyi. All rights reserved.
//

#import "ViewController.h"

#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height

@interface ViewController ()<CAAnimationDelegate>

@property (strong, nonatomic) UIImageView *customImageView;
@property (strong, nonatomic) UILabel *label;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.customImageView = [[UIImageView alloc] init];
    self.customImageView.frame = CGRectMake(0, 64, kScreenWidth, kScreenWidth);
    self.customImageView.backgroundColor = [UIColor redColor];
    self.customImageView.image = [UIImage imageNamed:@"0.jpg"];
    [self.view addSubview:self.customImageView];

    self.label = [[UILabel alloc] init];
    self.label.frame = CGRectMake(0, kScreenWidth + 100, kScreenWidth, 30);
    self.label.text = @"奥黛丽·赫本";
    self.label.textColor = [UIColor blackColor];
    self.label.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:self.label];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    // 创建过渡动画
    CATransition *transition = [[CATransition alloc] init];

    // 设置好过渡动画的代理
    transition.delegate = self;

    // 设置过渡动画类型、子类型、时间曲线及其它一些设置
    transition.type = @"rippleEffect";
    transition.subtype = kCATransitionFromTop;
    transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    transition.duration = 3;

    // 设置图层的新外观
    NSInteger num = arc4random()%7;
    self.customImageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%ld.jpg", num]];
    switch (num) {
        case 0:
            self.label.text = @"奥黛丽·赫本";
            break;
        case 1:
            self.label.text = @"苏菲·玛索";
            break;
        case 2:
            self.label.text = @"泰勒·斯威夫特";
            break;
        case 3:
            self.label.text = @"安妮·海瑟薇";
            break;
        case 4:
            self.label.text = @"娜塔丽·波特曼";
            break;
        case 5:
            self.label.text = @"凯拉·奈特利";
            break;
        case 6:
            self.label.text = @"杰西卡·阿尔芭";
            break;
    }

    // 把过渡动画添加到layer上
    [self.customImageView.layer addAnimation:transition forKey:nil];
    [self.label.layer addAnimation:transition forKey:nil];
}

- (void)animationDidStart:(CAAnimation *)anim {

    NSLog(@"动画开始了");
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {

    NSLog(@"动画结束了");
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
1.gif

四、什么情况下使用显示动画

针对基础动画:用UIView block基础动画和layer的隐式动画就够了,layer的显式动画的基础动画也没多啥,用起来反而累赘。

针对关键帧动画:一般情况下使用UIView block关键帧动画就可以,但是如果是需要连续关键帧的场景就需要使用layer的显式动画的关键帧动画。

针对过渡动画:一般情况下使用UIView block过渡动画就可以,但是如果是需要更丰富动画效果的场景可以使用layer的显式动画的过渡动画。

总的来说,我们暂时还没有必要直接创建layer来做动画,开发中正常用UIView就可以了,UIView block动画就不说了,隐式动画和显示动画也都是可以间接或直接地作用于view关联的layer的。

上一篇 下一篇

猜你喜欢

热点阅读