501-核心动画

一、Core Animation(核心动画)

1.简介

  1)Core Animation:中文翻译为核心动画,它是一组很强大的动画处理的API。可用在Mac OS X和iOS平台

  2)Core Animation的动画执行过程都是在后台操作的,不会阻塞主线程

  3)Core Animation是直接作用在CALayer上的,并非是UIView

2.使用步骤

  1)使用它需要先添加QuartzCore.framework框架(iOS7以后无需导入框架)

  2)引入主头文件<QuartzCore/QuartzCore.h>

  3)初始化一个CAAnimation对象,并设置一些动画相关属性

  4)通过调用CALayer的addAnimation:forKey:方法增加CAAnimation对象到CALayer中,这样就开始动画啦

  5)通过调用CALayer的removeAnimationForKey:方法可以停止CALayer中的动画

3.transform的属性列表(官方文档搜索“transform value key paths”)

  

 

二、CAAnimation

1.CAAnimation的几个子类

  1)执行动画之前,必须先初始化一个CAAnimation对象,

  2)我们在使用中并不是直接使用CAAnimation这个类,而是使用的是它的几个子类

  

2.CAAnimation的几个重要属性和方法

  1)控制动画运行的节奏

    @property(nullable, strong) CAMediaTimingFunction *timingFunction;

    kCAMediaTimingFunctionLinear  // 匀速

    kCAMediaTimingFunctionEaseIn  // 渐进

    kCAMediaTimingFunctionEaseOut  // 渐出

    kCAMediaTimingFunctionEaseInEaseOut  // 渐进渐出

    kCAMediaTimingFunctionDefault  // 默认

  2)动画的持续时间(默认为0,所以动画必须设置该属性)

    @property CFTimeInterval duration;

  3)动画的重复次数(默认为0,不重复)

    @property float repeatCount;

  4)协议代理(这个代理无需增收任何协议,协议为NSObject的分类方法)

    @property(nullable, strong) id delegate;   

1 @interface NSObject (CAAnimationDelegate)
2 
3 #pragma mark - 动画开始执行
4 - (void)animationDidStart:(CAAnimation *)anim;
5 
6 #pragma mark - 动画执行完毕
7 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
8 
9 @end

  5)保持动画执行后的状态(默认为YES)

    @property(getter=isRemovedOnCompletion) BOOL removedOnCompletion;

  6)决定当前对象在非active时间段的行为(比如:动画执行前和动画执行后) -- fillMode有效,必须设置removedOnCompletion为NO

    @property(copy) NSString *fillMode;

    kCAFillModeRemoved 默认值,动画前后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态

    kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态

    kCAFillModeBackwards 在动画开始前,只需要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始。

    kCAFillModeBoth 这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态
  7)动画延迟执行时间
    @property CFTimeInterval beginTime;

  8)初始化方法

    + (instancetype)animation;

  总结:1)以上几个属性和方法Core Animation子类都可以使用。

     2)开发中只能使用Core Animation的子类,但是子类CAPropertyAnimation也是不能直接使用,也是使用它的子类:

      a.CABasicAnimation

      b.CAKeyframeAnimation

      c.CATransition

      d.CAAnimationGroup

3.暂停和恢复动画

  1)暂停动画

 1 #pragma mark - 暂停动画
 2 - (void)pauseLayer:(CALayer*)layer
 3 {
 4     // 获取当前动画的时刻
 5     CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
 6     
 7     // 让CALayer的时间停止走动
 8     layer.speed = 0.0;
 9     
10     // 让CALayer的时间停留在pausedTime这个时刻
11     layer.timeOffset = pausedTime;
12 }

  2)恢复动画

 1 #pragma mark 恢复动画
 2 -(void)resumeLayer:(CALayer*)layer
 3 {
 4     // 获取暂停动画的时刻
 5     CFTimeInterval pausedTime = layer.timeOffset;
 6     
 7     // 让CALayer的时间继续行走
 8     layer.speed = 1.0;
 9     
10     // 取消上次记录的停留时刻
11     layer.timeOffset = 0.0;
12     
13     // 取消上次设置的时间
14     layer.beginTime = 0.0;
15     
16     // 计算暂停的时间(这里也可以用CACurrentMediaTime() - pausedTime)
17     CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
18     
19     // 设置相对于父坐标系的开始时间(往后退timeSincePause)
20     layer.beginTime = timeSincePause;
21 }

 

三、CAPropertyAnimation(CAAnimation的子类)

 1.简介

  1)CApropertyAnimation是CAAnimation的子类,但是开发中也不能直接使用。要想创建动画对象,使用的时它的两个子类:

    a.CABasicAnimation

    b.CAKeyframeAnimation

2.CAPropertyAnimation的几个属性和方法

  1)指定CALayer的属性名

    @property(nullable, copy) NSString *keyPath;

  2)初始化方法

    + (instancetype)animationWithKeyPath:(nullable NSString *)path;

  总结:以上属性和方法对于它的两个子类:CABasicAnimation和CAKeyframeAnimation也都是存在的

 

四、CABasicAnimation(CAPropertyAnimation的子类)

1.简介

  1)CABasicAnimation是CAPropertyAnimation的子类,使用它可以实现一些基本的动画效果

  2)动画效果:可以让CALayer的属性值从某一个值渐变到另一个值

2.CABasicAnimation的几个属性

  1)CALayer的属性动画起始值

    @property(nullable, strong) id fromValue;

  2)CALayer的属性动画终止值

    @property(nullable, strong) id toValue;

  3)CALayer的属性动画的累加值

    @property(nullable, strong) id byValue;

3.代码示例

  1 // ViewController.m文件
  2 #import "ViewController.h"
  3 #import <QuartzCore/QuartzCore.h> // 导入头文件
  4 
  5 @interface ViewController ()
  6 
  7 // 成员属性(待动画的View)
  8 @property (nonatomic, strong) UIView *myView;
  9 
 10 @end
 11 
 12 @implementation ViewController
 13 
 14 - (void)viewDidLoad {
 15     [super viewDidLoad];
 16     
 17     // 创建myView
 18     _myView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 50, 50)];
 19     _myView.backgroundColor = [UIColor redColor];
 20     [self.view addSubview:_myView];
 21     
 22     UIImageView *imageView = [[UIImageView alloc] initWithFrame:_myView.bounds];
 23     imageView.image = [UIImage imageNamed:@"1.jpg"];
 24     [_myView addSubview:imageView];
 25 }
 26 
 27 #pragma mark - 点击空白处
 28 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
 29 {
 30     // 平移动画
 31     // [self translationAnimationOne]; // 方法一
 32     // [self translationAnimationTwo]; // 方法二
 33     
 34     // 缩放动画
 35     // [self scaleAnimationOne]; // 方法一
 36     // [self scaleAnimationTwo]; // 方法二
 37     
 38     // 旋转动画
 39     [self rotationAnimation];
 40 }
 41 
 42 #pragma mark - 平移动画
 43 // 1.方法一
 44 - (void)translationAnimationOne
 45 {
 46     // 1.创建动画对象
 47     // 参数:keyPath 字符串类型 需要进行动画改变的CALayer属性
 48     CABasicAnimation *basicAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
 49     
 50     // 2.动画设置
 51     // 动画持续时间
 52     basicAnimation.duration = 5;
 53     // 动画重复次数
 54     basicAnimation.repeatCount = 5;
 55     // 动画运行节奏
 56     // kCAMediaTimingFunctionLinear // 匀速
 57     // kCAMediaTimingFunctionEaseIn // 渐进
 58     // kCAMediaTimingFunctionEaseOut // 渐出
 59     // kCAMediaTimingFunctionEaseInEaseOut // 渐进渐出
 60     // kCAMediaTimingFunctionDefault // 默认
 61     basicAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
 62     // 动画代理(这个代理不需要遵循任何协议,说明该协议方法只是NSObject的一个分类)
 63     basicAnimation.delegate = self;
 64     // 保持动画执行后的状态
 65     basicAnimation.removedOnCompletion = NO;
 66     basicAnimation.fillMode = kCAFillModeForwards;
 67     
 68     // 3.动画设置值
 69     // position属性是CGPoint类型,必须包装成NSValue对象类型
 70     // anchorPoint默认为中点
 71     // 中点从(0, 0)到(300, 300)
 72     basicAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];
 73     basicAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(300, 300)];
 74     
 75     // 4.添加动画对象到图层上
 76     // 参数1:动画对象
 77     // 参数2:动画名称(标记不同动画,方便移除指定动画)
 78     [_myView.layer addAnimation:basicAnimation forKey:@"basicAnimation1"];
 79 }
 80 // 2.方法二
 81 - (void)translationAnimationTwo
 82 {
 83     // 1.创建动画对象
 84     // 参数:keyPath 字符串类型 需要进行动画改变的CALayer属性
 85     CABasicAnimation *basicAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
 86     
 87     // 2.动画设置
 88     // 动画持续时间
 89     basicAnimation.duration = 30;
 90     // 动画代理(这个代理不需要遵循任何协议,说明该协议方法只是NSObject的一个分类)
 91     basicAnimation.delegate = self;
 92     // 保持动画执行后的状态
 93     basicAnimation.removedOnCompletion = NO;
 94     basicAnimation.fillMode = kCAFillModeForwards;
 95     
 96     // 3.动画设置值
 97     // transform:CATransform3DMakeTranslation(tx, ty, tz)
 98     // 从动画的View的原始起点开始,X轴右移300,Y轴下移300,Z轴不动
 99     basicAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(300, 300, 0)];
100     
101     // 4.添加动画对象到图层上
102     // 参数1:动画对象
103     // 参数2:动画名称(标记不同动画,方便移除指定动画)
104     [_myView.layer addAnimation:basicAnimation forKey:@"basicAnimation2"];
105 }
106 
107 #pragma mark - 缩放动画
108 // 1.方法一
109 - (void)scaleAnimationOne
110 {
111     // 1.创建动画对象
112     // 参数:keyPath 字符串类型 需要进行动画改变的CALayer属性
113     CABasicAnimation *basicAnimation = [CABasicAnimation animationWithKeyPath:@"bounds"];
114     
115     // 2.动画设置
116     // 动画持续时间
117     basicAnimation.duration = 30;
118     // 动画代理(这个代理不需要遵循任何协议,说明该协议方法只是NSObject的一个分类)
119     basicAnimation.delegate = self;
120     // 保持动画执行后的状态
121     basicAnimation.removedOnCompletion = NO;
122     basicAnimation.fillMode = kCAFillModeForwards;
123     
124     // 3.动画设置值
125     // 起始200*200缩小到100*100
126     basicAnimation.fromValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 200, 200)];
127     basicAnimation.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 100, 100)];
128     
129     // 4.添加动画对象到图层上
130     // 参数1:动画对象
131     // 参数2:动画名称(标记不同动画,方便移除指定动画)
132     [_myView.layer addAnimation:basicAnimation forKey:@"basicAnimation3"];
133 }
134 // 2.方法二
135 - (void)scaleAnimationTwo
136 {
137     // 1.创建动画对象
138     // 参数:keyPath 字符串类型 需要进行动画改变的CALayer属性
139     CABasicAnimation *basicAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
140     
141     // 2.动画设置
142     // 动画持续时间
143     basicAnimation.duration = 30;
144     // 动画代理(这个代理不需要遵循任何协议,说明该协议方法只是NSObject的一个分类)
145     basicAnimation.delegate = self;
146     // 保持动画执行后的状态
147     basicAnimation.removedOnCompletion = NO;
148     basicAnimation.fillMode = kCAFillModeForwards;
149     
150     // 3.动画设置值
151     // 起始动画View:原始View的宽缩小为一半,高缩小为一半,Z轴不变
152     // 结束动画View:原始View的宽扩大为二倍,高扩大为三倍,Z轴不变
153     basicAnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.5, 0.5, 1)];
154     basicAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(2, 3, 1)];
155     
156     // 4.添加动画对象到图层上
157     // 参数1:动画对象
158     // 参数2:动画名称(标记不同动画,方便移除指定动画)
159     [_myView.layer addAnimation:basicAnimation forKey:@"basicAnimation4"];
160 }
161 
162 #pragma mark - 旋转动画
163 - (void)rotationAnimation
164 {
165     // 1.创建动画对象
166     // 参数:keyPath 字符串类型 需要进行动画改变的CALayer属性
167     CABasicAnimation *basicAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
168     
169     // 2.动画设置
170     // 动画持续时间
171     basicAnimation.duration = 30;
172     // 动画代理(这个代理不需要遵循任何协议,说明该协议方法只是NSObject的一个分类)
173     basicAnimation.delegate = self;
174     // 保持动画执行后的状态
175     basicAnimation.removedOnCompletion = NO;
176     basicAnimation.fillMode = kCAFillModeForwards;
177     
178     // 3.动画设置值
179     // 沿着(0, 0, 1)这个向量方向旋转45°角
180     basicAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_4, 0, 0, 1)];
181     
182     // 4.添加动画对象到图层上
183     // 参数1:动画对象
184     // 参数2:动画名称(标记不同动画,方便移除指定动画)
185     [_myView.layer addAnimation:basicAnimation forKey:@"basicAnimation5"];
186 }
187 
188 #pragma mark - 协议方法<CAAnimationDelegate>
189 // 1.动画开始
190 - (void)animationDidStart:(CAAnimation *)anim
191 {
192     NSLog(@"动画开始");
193 }
194 // 2.动画结束
195 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
196 {
197     NSLog(@"动画结束");
198 }
199 
200 @end

  总结:1)CABasicAnimation只能是从一个值到一个值(两个值之间的切换),有一定的局限性

     2)如果将以上代码是咧中属性值toValue换成byValue,就变成了在原有基础上的累计

 

五、CAKeyframeAnimation(CAPropertyAnimation的子类)

1.简介

  1)CAkeyframeAnimation:意思就是“帧动画”,也是CAPropertyAnimation的子类。

  2)解决了CABasicAnimation的两个值切换的局限性,可以实现多个值之间的切换

2.CAKeyframeAnimation的几个属性

  1)切换值数组

    @property(nullable, copy) NSArray *values;

  2)动画每一帧的时间(其取值范围为0-1,默认为等分)

    @property(nullable, copy) NSArray<NSNumber *> *keyTimes;

  3)动画行走轨迹

    @property(nullable) CGPathRef path;

3.代码示例

  1)基本示例

  1 // ViewController.m文件
  2 #import "ViewController.h"
  3 #import <QuartzCore/QuartzCore.h> // 导入头文件
  4 
  5 @interface ViewController ()
  6 
  7 // 成员属性(待动画的View)
  8 @property (nonatomic, strong) UIView *myView;
  9 
 10 @end
 11 
 12 @implementation ViewController
 13 
 14 - (void)viewDidLoad {
 15     [super viewDidLoad];
 16     
 17     // 创建myView
 18     _myView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 50, 50)];
 19     _myView.backgroundColor = [UIColor redColor];
 20     [self.view addSubview:_myView];
 21     
 22     UIImageView *imageView = [[UIImageView alloc] initWithFrame:_myView.bounds];
 23     imageView.image = [UIImage imageNamed:@"1.jpg"];
 24     [_myView addSubview:imageView];
 25 }
 26 
 27 #pragma mark - 点击空白处
 28 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
 29 {
 30     // 平移动画
 31     // [self translationAnimation];
 32     
 33     // 指定轨迹动画
 34     [self pathAnimation];
 35 }
 36 
 37 #pragma mark - 平移动画
 38 - (void)translationAnimation
 39 {
 40     // 1.创建动画对象
 41     // 初始化方法1:父类(CAPropertyAnimation)的方法
 42     // 参数:keyPath 字符串类型 需要进行动画改变的CALayer属性
 43     CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
 44     // 初始化方法2:父类(CAPropertyAnimation)的父类(CAAnimation)的方法
 45     // CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animation];
 46     // keyframeAnimation.keyPath = @"position";
 47     
 48     // 2.动画设置
 49     // 动画持续时间
 50     keyframeAnimation.duration = 1.5;
 51     // 动画每一帧的时间(默认为平分,取值范围为0-1)
 52     // keyframeAnimation.keyTimes = @[@(0.5), @(0.5), @(0.25), @(0.25)];
 53     // 动画运行节奏
 54     // kCAMediaTimingFunctionLinear // 匀速
 55     // kCAMediaTimingFunctionEaseIn // 渐进
 56     // kCAMediaTimingFunctionEaseOut // 渐出
 57     // kCAMediaTimingFunctionEaseInEaseOut // 渐进渐出
 58     // kCAMediaTimingFunctionDefault // 默认
 59     keyframeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
 60     // 动画代理(这个代理不需要遵循任何协议,说明该协议方法只是NSObject的一个分类)
 61     keyframeAnimation.delegate = self;
 62     // 保持动画执行后的状态
 63     keyframeAnimation.removedOnCompletion = NO;
 64     keyframeAnimation.fillMode = kCAFillModeForwards;
 65     
 66     // 3.动画设置值(共4帧)
 67     NSValue *value1 = [NSValue valueWithCGPoint:CGPointZero];
 68     NSValue *value2 = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
 69     NSValue *value3 = [NSValue valueWithCGPoint:CGPointMake(20, 30)];
 70     NSValue *value4 = [NSValue valueWithCGPoint:CGPointMake(200, 50)];
 71     NSValue *value5 = [NSValue valueWithCGPoint:CGPointMake(150, 300)];
 72     keyframeAnimation.values = @[value1, value2, value3, value4, value5];
 73     
 74     // 4.添加动画对象到图层上
 75     // 参数1:动画对象
 76     // 参数2:动画名称(标记不同动画,方便移除指定动画)
 77     [_myView.layer addAnimation:keyframeAnimation forKey:@"keyframeAnimation1"];
 78 }
 79 
 80 #pragma mark - 指定轨迹动画
 81 - (void)pathAnimation
 82 {
 83     // 1.创建动画对象
 84     // 初始化方法1:父类(CAPropertyAnimation)的方法
 85     // 参数:keyPath 字符串类型 需要进行动画改变的CALayer属性
 86     CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
 87     // 初始化方法2:父类(CAPropertyAnimation)的父类(CAAnimation)的方法
 88     // CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animation];
 89     // keyframeAnimation.keyPath = @"position";
 90     
 91     // 2.动画设置
 92     // 动画持续时间
 93     keyframeAnimation.duration = 1.0;
 94     // 动画每一帧的时间(默认为平分,取值范围为0-1)
 95     // keyframeAnimation.keyTimes = @[@(0.2), @(0.1), @(0.5), @(0.2)];
 96     // 动画代理(这个代理不需要遵循任何协议,说明该协议方法只是NSObject的一个分类)
 97     keyframeAnimation.delegate = self;
 98     // 保持动画执行后的状态
 99     keyframeAnimation.removedOnCompletion = NO;
100     keyframeAnimation.fillMode = kCAFillModeForwards;
101     
102     // 3.动画设置值
103     CGMutablePathRef path = CGPathCreateMutable();
104     CGPathAddEllipseInRect(path, NULL, CGRectMake(100, 100, 100, 100));
105     keyframeAnimation.path = path;
106     CGPathRelease(path); // CG类型Create出来的必须释放
107     
108     // 4.添加动画对象到图层上
109     // 参数1:动画对象
110     // 参数2:动画名称(标记不同动画,方便移除指定动画)
111     [_myView.layer addAnimation:keyframeAnimation forKey:@"keyframeAnimation2"];
112 }
113 
114 #pragma mark - 协议方法<CAAnimationDelegate>
115 // 1.动画开始
116 - (void)animationDidStart:(CAAnimation *)anim
117 {
118     NSLog(@"动画开始");
119 }
120 // 2.动画结束
121 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
122 {
123     NSLog(@"动画结束");
124 }
125 
126 @end

  2)图标抖动

  1 // ViewController.m文件
  2 #import "ViewController.h"
  3 #import <QuartzCore/QuartzCore.h> // 导入头文件
  4 
  5 @interface ViewController ()
  6 
  7 // 成员属性(待动画的View)
  8 @property (nonatomic, strong) UIView *myView;
  9 @property (nonatomic, strong) UIImageView *imageView;
 10 
 11 @end
 12 
 13 @implementation ViewController
 14 
 15 - (void)viewDidLoad {
 16     [super viewDidLoad];
 17     
 18     // 创建myView
 19     _myView = [[UIView alloc] init];
 20     _myView.bounds = CGRectMake(0, 0, 90, 90);
 21     _myView.center = CGPointMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height / 2.0);
 22     _myView.layer.cornerRadius = 10;
 23     [self.view addSubview:_myView];
 24     
 25     // 创建imageView
 26     _imageView = [[UIImageView alloc] initWithFrame:_myView.bounds];
 27     _imageView.image = [UIImage imageNamed:@"1.jpg"];
 28     _imageView.layer.cornerRadius = 10;
 29     _imageView.layer.masksToBounds = YES;
 30     _imageView.userInteractionEnabled = YES; // 打开交互
 31     [_myView addSubview:_imageView];
 32     
 33     // 添加长按手势
 34     UILongPressGestureRecognizer *tap = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(tapClick:)];
 35     tap.minimumPressDuration = 1;
 36     [_imageView addGestureRecognizer:tap];
 37 }
 38 
 39 #pragma mark - 长按手势的点击事件
 40 - (void)tapClick:(UILongPressGestureRecognizer *)tap
 41 {
 42     // 添加一个删除的按钮
 43     UIButton *deleteBtn = [UIButton buttonWithType:UIButtonTypeSystem];
 44     deleteBtn.bounds = CGRectMake(0, 0, 25, 25);
 45     deleteBtn.center = CGPointMake(5, 5);
 46     deleteBtn.backgroundColor = [UIColor redColor];
 47     deleteBtn.layer.cornerRadius = deleteBtn.bounds.size.width / 2.0;
 48     deleteBtn.layer.masksToBounds = YES;
 49     deleteBtn.tag = 10;
 50     [deleteBtn addTarget:self action:@selector(deleteBtnClick:) forControlEvents:UIControlEventTouchUpInside];
 51     [_myView addSubview:deleteBtn];
 52     
 53     UIView *lineView = [[UIView alloc] init];
 54     lineView.bounds = CGRectMake(0, 0, deleteBtn.bounds.size.width, 1);
 55     lineView.center = CGPointMake(deleteBtn.bounds.size.width / 2.0, deleteBtn.bounds.size.height / 2.0);
 56     lineView.backgroundColor = [UIColor whiteColor];
 57     [deleteBtn addSubview:lineView];
 58     
 59     // 图标抖动
 60     [self vibrationAnimation];
 61 }
 62 
 63 #pragma mark - 删除按钮的点击事件
 64 - (void)deleteBtnClick:(UIButton *)btn
 65 {
 66     // 移除动画
 67     [_myView.layer removeAnimationForKey:@"keyframeAnimation"];
 68 
 69     // 删除myView
 70     [_myView removeFromSuperview];
 71 }
 72 
 73 #pragma mark - 图标抖动动画
 74 - (void)vibrationAnimation
 75 {
 76     // 1.创建动画对象
 77     CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animation];
 78     keyframeAnimation.keyPath = @"transform.rotation";
 79     
 80     // 2.动画设置
 81     // 动画持续时间
 82     keyframeAnimation.duration = 0.25;
 83     // 动画重复次数
 84     keyframeAnimation.repeatCount = 1000;
 85     // 动画代理(这个代理不需要遵循任何协议,说明该协议方法只是NSObject的一个分类)
 86     keyframeAnimation.delegate = self;
 87     // 保持动画执行后的状态
 88     keyframeAnimation.removedOnCompletion = NO;
 89     keyframeAnimation.fillMode = kCAFillModeForwards;
 90     
 91     // 3.动画设置值
 92     CGFloat radian1 = [self radianWithAngle:-5];
 93     CGFloat radian2 = [self radianWithAngle:5];
 94     keyframeAnimation.values = @[@(radian1), @(radian2), @(radian1)];
 95     
 96     // 4.添加动画对象到图层上
 97     // 参数1:动画对象
 98     // 参数2:动画名称(标记不同动画,方便移除指定动画)
 99     [_myView.layer addAnimation:keyframeAnimation forKey:@"keyframeAnimation"];
100 }
101 
102 #pragma mark - 角度转弧度
103 - (CGFloat)radianWithAngle:(CGFloat)angle
104 {
105     return angle / 180.0 * M_PI;
106 }
107 
108 #pragma mark - 协议方法<CAAnimationDelegate>
109 // 1.动画开始
110 - (void)animationDidStart:(CAAnimation *)anim
111 {
112     NSLog(@"动画开始");
113 }
114 // 2.动画结束
115 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
116 {
117     NSLog(@"动画结束");
118 }
119 
120 @end

 

六、CATransition(CAAnimation的子类)

1.简介

  1)CATransition:意思是“过度动画”,是CAAnimation的子类

  2)通常用来做一些切换效果

2.CATransition的几个属性

  1)动画过渡类型

    @property(copy) NSString *type;

    

  2)动画过渡方向

    @property(nullable, copy) NSString *subtype;

    // kCATransitionFromRight

    // kCATransitionFromLeft 

    // kCATransitionFromTop

    // kCATransitionFromBottom

  3)动画翻转起点(百分比,取值为0-1)

    @property float startProgress;

  4)动画翻转终点(百分比,取值为0-1)

    @property float endProgress;

3.代码示例

  1 // ViewController.m文件
  2 #import "ViewController.h"
  3 #import <QuartzCore/QuartzCore.h> // 导入头文件
  4 
  5 // 图片总数
  6 #define kImageCount 6
  7 
  8 @interface ViewController ()
  9 
 10 // 动画切换的imageView
 11 @property (nonatomic, strong) UIImageView *imageView;
 12 // 下一张
 13 @property (nonatomic, strong) UIButton *frontBtn;
 14 // 上一张
 15 @property (nonatomic, strong) UIButton *backBtn;
 16 // 当前图片的索引
 17 @property (nonatomic, assign) int index;
 18 
 19 @end
 20 
 21 @implementation ViewController
 22 
 23 - (void)viewDidLoad
 24 {
 25     [super viewDidLoad];
 26     
 27     // 创建imageView
 28     _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(30, 40, self.view.bounds.size.width - 30 * 2, self.view.bounds.size.height - 150)];
 29     _imageView.image = [UIImage imageNamed:@"1.jpg"];
 30     _imageView.userInteractionEnabled = YES; // 打开交互
 31     [self.view addSubview:_imageView];
 32     
 33     // 下一张
 34     _frontBtn = [UIButton buttonWithType:UIButtonTypeSystem];
 35     _frontBtn.frame = CGRectMake(30, CGRectGetMaxY(_imageView.frame) + 20, _imageView.bounds.size.width / 2.0 - 20, 50);
 36     [_frontBtn setTitle:@"下一张" forState:UIControlStateNormal];
 37     _frontBtn.tintColor = [UIColor whiteColor];
 38     _frontBtn.titleLabel.font = [UIFont boldSystemFontOfSize:20];
 39     _frontBtn.backgroundColor = [UIColor redColor];
 40     _frontBtn.layer.cornerRadius = 10;
 41     _frontBtn.tag = 10;
 42     [_frontBtn addTarget:self action:@selector(frontBtnClick:) forControlEvents:UIControlEventTouchUpInside];
 43     [self.view addSubview:_frontBtn];
 44     
 45     // 上一张
 46     _backBtn = [UIButton buttonWithType:UIButtonTypeSystem];
 47     _backBtn.frame = CGRectMake(CGRectGetMaxX(_frontBtn.frame) + 40, _frontBtn.frame.origin.y, _frontBtn.frame.size.width, _frontBtn.frame.size.height);
 48     [_backBtn setTitle:@"上一张" forState:UIControlStateNormal];
 49     _backBtn.tintColor = [UIColor whiteColor];
 50     _backBtn.titleLabel.font = [UIFont boldSystemFontOfSize:20];
 51     _backBtn.backgroundColor = [UIColor redColor];
 52     _backBtn.layer.cornerRadius = 10;
 53     _backBtn.tag = 11;
 54     [_backBtn addTarget:self action:@selector(backBtnClick:) forControlEvents:UIControlEventTouchUpInside];
 55     [self.view addSubview:_backBtn];
 56     
 57     // 当前图片索引为1
 58     _index = 1;
 59     // 当前禁用backBtn
 60     _backBtn.enabled = NO;
 61     _backBtn.backgroundColor = [UIColor lightGrayColor];
 62     
 63     
 64 }
 65 
 66 #pragma mark - 点击事件
 67 // 1.下一张
 68 - (void)frontBtnClick:(UIButton *)btn
 69 {
 70     // 当前图片索引+1
 71     _index++;
 72     
 73     // 启用backBtn
 74     if (_index == 1 + 1) {
 75         _backBtn.enabled = YES;
 76         _backBtn.backgroundColor = [UIColor redColor];
 77     }
 78     
 79     // 判断是否到最后一张,最后一张禁用frontBtn
 80     if (_index == kImageCount) {
 81         _frontBtn.enabled = NO;
 82         _frontBtn.backgroundColor = [UIColor lightGrayColor];
 83     }
 84     
 85     // 切换图片
 86     NSString *imageName = [NSString stringWithFormat:@"%d.jpg", _index];
 87     _imageView.image = [UIImage imageNamed:imageName];
 88     
 89     // 1.创建转场动画对象
 90     CATransition *transition = [CATransition animation];
 91     
 92     // 2.设置转场动画属性
 93     // 动画样式
 94     transition.type = @"pageCurl";
 95     // 过渡方向
 96     // kCATransitionFromRight
 97     // kCATransitionFromLeft
 98     // kCATransitionFromTop
 99     // kCATransitionFromBottom
100     transition.subtype = kCATransitionFromRight;
101     // 设置翻转起点
102     transition.startProgress = 0.3;
103     // 设置翻转终点
104     transition.endProgress = 0.8;
105     // 动画时间
106     transition.duration = 0.5;
107     // 设置代理
108     transition.delegate = self;
109     
110     // 3.添加动画
111     [_imageView.layer addAnimation:transition forKey:@"transition"];
112 }
113 // 2.上一张
114 - (void)backBtnClick:(UIButton *)btn
115 {
116     // 当前图片索引-1
117     _index--;
118     
119     // 启用frontBtn
120     if (_index == kImageCount - 1) {
121         _frontBtn.enabled = YES;
122         _frontBtn.backgroundColor = [UIColor redColor];
123     }
124     
125     // 判断是否第一张,最后一张禁用backBtn
126     if (_index == 1) {
127         _backBtn.enabled = NO;
128         _backBtn.backgroundColor = [UIColor lightGrayColor];
129     }
130     
131     // 切换图片
132     NSString *imageName = [NSString stringWithFormat:@"%d.jpg", _index];
133     _imageView.image = [UIImage imageNamed:imageName];
134     
135     
136     // 1.创建转场动画对象
137     CATransition *transition = [CATransition animation];
138     
139     // 2.设置转场动画属性
140     // 动画样式
141     transition.type = @"pageCurl";
142     // 过渡方向
143     // kCATransitionFromRight
144     // kCATransitionFromLeft
145     // kCATransitionFromTop
146     // kCATransitionFromBottom
147     transition.subtype = kCATransitionFromLeft;
148     // 设置翻转起点
149     transition.startProgress = 0.3;
150     // 设置翻转终点
151     transition.endProgress = 0.8;
152     // 动画时间
153     transition.duration = 0.5;
154     // 设置代理
155     transition.delegate = self;
156     
157     // 3.添加动画
158     [_imageView.layer addAnimation:transition forKey:@"transition"];
159 } 
160 
161 #pragma mark - 协议方法<CAAnimationDelegate>
162 // 1.动画开始
163 - (void)animationDidStart:(CAAnimation *)anim
164 {
165     NSLog(@"动画开始");
166 }
167 // 2.动画结束
168 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
169 {
170     NSLog(@"动画结束");
171 }
172 
173 @end

 

七、CAAnimationGroup(CAAnimation的子类)

1.简介

  1)CAAnimationGroup:意思是“动画组”,是CAAnimation的子类

  2)它可以保存一组动画对象。给图层添加CAAnimationGroup后,组中所有动画对象可以同时并发运行

2.CAAnimationGroup的几个属性

  1)动画数组

  @property(nullable, copy) NSArray<CAAnimation *> *animations;

  默认情况下,一组动画对象是同时运行的,也可以通过设置动画对象的beginTime属性来更改动画的开始时间

3.代码示例

 1 // ViewController.m文件
 2 #import "ViewController.h"
 3 #import <QuartzCore/QuartzCore.h> // 导入头文件
 4 
 5 @interface ViewController ()
 6 
 7 // 成员属性
 8 @property (nonatomic, strong) UIView *myView;
 9 
10 @end
11 
12 @implementation ViewController
13 
14 - (void)viewDidLoad
15 {
16     [super viewDidLoad];
17     
18     // 创建myView
19     _myView = [[UIView alloc] initWithFrame:CGRectMake(30, 100, 200, 200)];
20     _myView.backgroundColor = [UIColor redColor];
21     [self.view addSubview:_myView];
22 }
23 
24 #pragma mark - 点击空白处
25 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
26 {
27     // 1.创建动画组里面的动画
28     // 创建旋转动画
29     CABasicAnimation *rotate = [CABasicAnimation animation];
30     rotate.keyPath = @"transform.rotation";
31     rotate.toValue = @(M_PI);
32     // 创建缩小动画
33     CABasicAnimation *scale = [CABasicAnimation animation];
34     scale.keyPath = @"transform.scale";
35     scale.toValue = @(0.0);
36     // 创建平移动画
37     CABasicAnimation *move = [CABasicAnimation animation];
38     move.keyPath = @"transform.translation";
39     move.toValue = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
40     
41     // 2.创建动画组对象
42     CAAnimationGroup *group = [CAAnimationGroup animation];
43     
44     // 3.将动画添加到动画组
45     // 这里添加不论先后,反正默认是同时并发执行
46     group.animations = @[rotate, scale, move];
47     
48     // 4.设置动画组
49     // 设置动画组的动画时长
50     group.duration = 2.0;
51     // 设置动画组代理
52     group.delegate = self;
53     // 设置动画组动画保留最后状态
54     group.removedOnCompletion = NO;
55     group.fillMode = kCAFillModeForwards;
56     
57     // 5.添加动画组到图层
58     [_myView.layer addAnimation:group forKey:@"group"];
59 }
60 
61 #pragma mark - 协议方法<CAAnimationDelegate>
62 // 1.动画开始
63 - (void)animationDidStart:(CAAnimation *)anim
64 {
65     NSLog(@"动画开始");
66 }
67 // 2.动画结束
68 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
69 {
70     NSLog(@"动画结束");
71 }
72 
73 @end

 

posted @ 2016-03-16 18:01  Frank9098  阅读(185)  评论(0)    收藏  举报