移动开发(IOS) – 动画

1 篇文章 0 订阅

移动开发(IOS) – 动画

By docoder in 博客学习 on 2014/07/03

animation

1.CALayer 

1.1.学习核心动画之前,需要先理解 CALayer,因为核心动画操作的对象不是 UIView,而是 CALayer 。

1.2.CALayer 是核心动画的基础,可以做圆角、阴影、边框等效果 。

1.3.每个 UIView 内部都有一个 Layer 的属性 。

1.4.在实现核心动画时,本质上是将 CALayer 中的内容转换成位图,从而便于图形硬件的操纵 。

1.5.在 UIView 中 CALayer 只是一个类声明,因此需要添加 QuartzCore 框架 。

1.6.UIKit 框架只能应用在 iOS 而不能用于 Mac,但是 Quartz 2D 是可以跨平台的,因此在使用颜色时,不能直接使用 UIColor而需要将颜色转成 CGColor 。

1.7.修改图层相当于修改UIView属性,即修改了界面属性 。

1.8.形变属性既可以用形变函数指定,也可以用keyPath指定 。

1.9.创建视图对象时,视图会自己创建一个层,视图在绘图(如 drawRect: )时,会将内容画在自己的层上。当视图在层上完成绘图后,系统会将图层拷贝至屏幕。每个视图都有一个层,而每个图层又可以有多个子层 。

1.10.Layer 的设计目的不是为了取代视图,因此不能基于 CALayer 创建一个独立的可视化组件 。

1.11.Layer 的设计目的是提供视图的基本可视内容,从而提高动画的执行效率 。

1.12.除提供可视内容外,Layer 不负责视图的事件响应、内容绘制等工作,同时 Layer 不能参与到响应者链条中 。

1.13.CALayer 层次结构:

CALayer

1.14.CALayer 的使用说明

1.14.1.通过 UIView 的 layer 属性可以拿到对应的根层,这个层不允许重新创建,但可以往层里面添加子层(调用 CALayer 的 addSublayer )。

1.14.2.要具体使用CALayer,需要引入<QuartzCore/QuartzCore.h>。

1.14.3.获取当前图层或使用静态方法 layer 初始化 CALayer 后,可以设置以下属性:


bounds 宽度和高度
position 位置(默认指中心点,具体由 anchorPoint 决定)
anchorPoint 锚点( x,y 的范围都是 0-1 ),决定了 position 的含义
backgroundColor 背景颜色( CGColorRef 类型)
borderColor 边框颜色( CGColorRef 类型)
borderWidth 边框宽度
cornerRadius 圆角半径
contents 内容(比如设置为图片 CGImageRef )
transform 旋转、缩放、平移

1.14.4.虽然 CALayer 可以使用 frame,但最好还是使用 bounds 和 position。为层设置动画时,用 bounds 和 position 会方便一点。

1.14.5.注意锚点和位置的关系,以及在旋转转换时对图层的影响。

1.14.6.UIView 有一个 addSubview 方法,而 layer 有一个 addSubLayer 方法。

1.14.7.CALayer 中使用 CGColorRef 和 CGImageRef 的数据类型,而不用 UIColor 和 UIImage 。

1.14.8.可以通过 UIKi t对象的特定方法,可以得到 Core Graphics 对象,如 UIImage 的 CGImage 方法和 UIColor 的 CGColor 方法。

1.15.CALayer 的隐式动画属性

1.15.1.每一个 UIView 内部都默认关联着一个 CALayer,称这个 Layer 为 Root Layer。所有的非 Root Layer 都存在着隐式动画,隐式动画的默认时长为 1/4 秒。

1.15.2.当修改非 Root Layer 的部分属性时,相应的修改会自动产生动画效果,能执行隐式动画的属性被称为“可动画属性”,诸如:


bounds 缩放动画
position 平移动画
opacity 淡入淡出动画(改变透明度)
 … …  … …

1.15.3.如果要关闭默认的动画效果,可以通过动画事务方法实现:

1
2
3
4
[CATransaction begin];
[CATransaction setDisableActions: YES ];
// ...
[CATransaction commit];

1.16.在 CALayer 上绘图

1.16.1.创建一个 CALayer 的子类,然后覆盖 drawInContext: 方法,可以使用 Quartz2D API 在其中进行绘图。

1.16.2.设置 CALayer 的 delegate,然后让 delegate 实现 drawLayer:inContext: 方法进行绘图。

1.16.3.不能再将 UIView 设置为这个 CALayer 的 delegate,因为 UIView 对象已经是内部层的 delegate,再次设置会出问题。

1.16.4.无论使用哪种方法,都必须向层发送 setNeedsDisplay 消息,以触发相应绘图方法的调用。

1.17.CALayer、 UIView 以及上下文之间的关系:

1.17.1.当 UIView 收到 setNeedsDisplay 消息时,CALayer 会准备好一个 CGContextRef,然后向它的 delegate 即 UIView,发送消息,并且传入已经准备好的 CGContextRef 对象。UIView 在 drawLayer:inContext: 方法中会调用自己的 drawRect: 方法。

1.17.2.平时在 drawRect: 中通过 UIGraphicsGetCurrentContext() 获取的就是由 CALayer 传入的 CGContextRef 对象,在 drawRect: 中完成的所有绘图都会填入 CALayer 的 CGContextRef 中,然后被拷贝至屏幕。

1.17.3. CALayer 的 CGContextRef 用的是位图上下文( Bitmap Graphics Context )。

1.18.在实现核心动画时,本质上是将 CALayer 中的内容转换成位图,从而便于图形硬件的操纵。

2.Core Animation

2.1.Core Animation 是跨平台的,支持 iOS 环境和 Mac OS X 环境。

2.2.使用它需要先添加 QuartzCore.framework 和引入对应的框架 <QuartzCore/QuartzCore.h> 。

2.3.开发步骤:

2.3.1.初始化一个动画对象 ( CAAnimation ) 并设置一些动画相关属性。

2.3.2.CALayer 中很多属性都可以通过 CAAnimation 实现动画效果,包括:opacity、 position、 transform、 bounds、 contents 等( 可以在 API 文档中搜索: CALayer Animatable Properties )。

2.3.3.添加动画对象到层( CALayer )中,开始执行动画。

2.3.4.通过调用 CALayer 的 addAnimation:forKey 增加动画到层( CALayer )中,这样就能触发动画了。通过调用 removeAnimationForKey 可以停止层中的动画。

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

3.CAAnimation

3.1.CAAnimation 继承结构

CAAnimation

3.2.CAAnimation 是所有动画对象的父类,负责控制动画的持续时间和速度,是个抽象类,不能直接使用,应该使用它具体的子类。

3.3.属性说明:


duration (来自CAMediaTiming协议的属性)动画的持续时间
repeatCount (来自CAMediaTiming协议的属性)重复次数,无限循环可以设置 HUGE_VALF 或者 MAXFLOAT
repeatDuration (来自CAMediaTiming协议的属性)重复时间
removedOnCompletion 默认为 YES,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示动画执行后的状态,那就设置为 NO,不过还要设置 fillMode 为 kCAFillModeForwards
fillMode (来自CAMediaTiming协议的属性)决定当前对象在非active时间段的行为。比如动画开始之前或者动画结束之后
beginTime (来自CAMediaTiming协议的属性)可以用来设置动画延迟执行时间,若想延迟 2s,就设置为 CACurrentMediaTime()+2 , CACurrentMediaTime() 为图层的当前时间
timingFunction 速度控制函数,控制动画运行的节奏
delegate 动画代理

3.4.CAAnimation 的动画填充模式,fillMode 属性值(要想 fillMode 有效,最好设置 removedOnCompletion = NO ):

3.4.1.kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对 layer 都没有影响,动画结束后,layer 会恢复到之前的状态。

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

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

3.4.4.kCAFillModeBoth 这个其实就是上面两个的合成.动画加入后开始之前,layer 便处于动画初始状态,动画结束后 layer 保持动画最后的状态。

3.5.CAAnimation 的速度控制函数( CAMediaTimingFunction ):

3.5.1. kCAMediaTimingFunctionLinear (线性):匀速,给你一个相对静态的感觉。

3.5.2. kCAMediaTimingFunctionEaseIn (渐进):动画缓慢进入,然后加速离开。

3.5.3. kCAMediaTimingFunctionEaseOut (渐出):动画全速进入,然后减速的到达目的地。

3.5.4. kCAMediaTimingFunctionEaseInEaseOut (渐进渐出):动画缓慢的进入,中间加速,然后减速的到达目的地。这个是默认的动画行为。

3.6.CAAnimation 动画代理方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@interface NSObject (CAAnimationDelegate)
 
/* Called when the animation begins its active duration. */
 
- ( void )animationDidStart:(CAAnimation *)anim;
 
/* Called when the animation either completes its active duration or
  * is removed from the object it is attached to (i.e. the layer). 'flag'
  * is true if the animation reached the end of its active duration
  * without being removed. */
 
- ( void )animationDidStop:(CAAnimation *)anim finished:( BOOL )flag;
 
@end

3.7.CALayer上动画的暂停和恢复:

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

4.CAPropertyAnimation

4.1.CAPropertyAnimation 是 CAAnimation 的子类,也是个抽象类,要想创建动画对象,应该使用它的两个子类: CABasicAnimation, CAKeyframeAnimation 。

4.2.属性说明:


keyPath 通过指定 CALayer 的一个属性名称为 keyPath ( NSString 类型),并且对 CALayer 的这个属性的值进行修改,达到相应的动画效果。比如,指定 @”position” 为 keyPath,就修改 CALayer 的 position 属性的值,以达到平移的动画效果。

5.CABasicAnimation

5.1.基本 CABasicAnimation,是 CAPropertyAnimation 的子类。

5.2.属性说明:


fromValue keyPath 相应属性的初始值
toValue keyPath 相应属性的结束值

5.3.动画过程说明:

5.3.1.随着动画的进行,在长度为 duration 的持续时间内,keyPath 相应属性的值从 fromValue 渐渐地变为 toValue 。

5.3.2.keyPath 内容是 CALayer 的可动画 Animatable 属性。

5.3.3.如果 fillMode = kCAFillModeForwards 同时 removedOnComletion = NO ,那么在动画执行完毕后,图层会保持显示动画执行后的状态。但在实质上,图层的属性值还是动画执行前的初始值,并没有真正被改变 。

5.3.4.如果只是实现简单属性变化的动画效果,可以使用 UIView 的 block 动画替代基本动画。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/***平移***/
// 1. 实例化动画
// 如果没有指定图层的锚点(定位点)postion对应UIView的中心点
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath: @"position" ];
// 2. 设置动画属性
// 1) fromValue(myView的当前坐标) & toValue
[anim setToValue:[ NSValue valueWithCGPoint:point]];
// 2) 动画的时长
[anim setDuration:1.0f];
// 3) 设置代理
[anim setDelegate: self ];
// 4) 让动画停留在目标位置
/*
  *提示:通过设置动画在完成后不删除,以及向前填充,可以做到平移动画结束后,
  *UIView看起来停留在目标位置,但是其本身的frame并不会发生变化
  */
[anim setRemovedOnCompletion: NO ];
// forwards是逐渐逼近目标点
[anim setFillMode:kCAFillModeForwards];
// 5) 要修正坐标点的实际位置可以利用setValue方法
[anim setValue:[ NSValue valueWithCGPoint:point] forKey: @"targetPoint" ];
[anim setValue: @"translationTo" forKey: @"animationType" ];
// 3. 将动画添加到图层
// 将动画添加到图层之后,系统会按照定义好的属性开始动画,通常程序员不在与动画进行交互
[ self .myView.layer addAnimation:anim forKey: nil ];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/***代理方法***/
//动画开始(极少用)
- ( void )animationDidStart:(CAAnimation *)anim
{
     NSLog ( @"开始动画" );
}
//动画结束(通常在动画结束后,做动画的后续处理)
- ( void )animationDidStop:(CAAnimation *)anim finished:( BOOL )flag
{
     NSString *type = [anim valueForKey: @"animationType" ];
     if ([type isEqualToString: @"translationTo" ]) {
         // 1. 通过键值取出需要移动到的目标点
         CGPoint point = [[anim valueForKey: @"targetPoint" ]CGPointValue];
         NSLog ( @"目标点: %@" , NSStringFromCGPoint (point));
         // 2. 设置myView的坐标点
         [ self .myView setCenter:point];
     }
  NSLog ( @"结束动画,myView: %@" , NSStringFromCGRect ( self .myView.frame));
}
1
2
3
4
5
6
/***block 动画***/
[UIView animateWithDuration:1.0f animations:^{
     [ self .myView setCenter:location];
} completion:^( BOOL finished) {
     NSLog ( @"%@" , NSStringFromCGRect ( self .myView.frame));
}];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/***旋转动画***/
// 1. 实例化基本动画
// 默认按照z轴旋转
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath: @"transform.rotation.z" ];
[ self .myView.layer setAnchorPoint:CGPointMake(0, 0)];
// 2. 设置动画属性
// 不停的旋转
// 1) 旋转一周
[anim setToValue:@(2 * M_PI)];
// 2) 不停的旋转 - 动画循环播放
// HUGE_VALF 是一个非常大得浮点数,指定此数值可以认为动画无限循环,这里不要使用 MAXFLOAT
[anim setRepeatCount:HUGE_VALF];
[anim setDuration:0.5f];
// 3) 动画完成时删除
// 对于循环播放的动画效果,一定要将 removedOnCompletion 设置为 NO,否则无法恢复动画
[anim setRemovedOnCompletion: NO ];
// 3. 添加动画
// key 可以随便指定,用于判断图层中是否存在该动画
[ self .myView.layer addAnimation:anim forKey: @"rotationAnim" ];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/***缩放动画***/
// 1. 实例化基本动画
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath: @"transform.scale" ];
// 2. 设置动画属性
// fromValue & toValue
[anim setFromValue:@(1.0)];
// 从当前大小缩小到一半,然后恢复初始大小
[anim setToValue:@(0.5)];
// 自动翻转动画
[anim setAutoreverses: YES ];
// 动画时长
[anim setDuration:0.5f];
// 3. 将动画添加到图层
[ self .myView.layer addAnimation:anim forKey: nil ];

6.CAKeyframeAnimation

6.1.CAKeyframeAnimation ,也是 CAPropertyAnimation 的子类。

6.2.与 CABasicAnimation 的区别是:

6.2.1.CABasicAnimation 只能从一个数值( fromValue )变到另一个数值( toValue ),而 CAKeyframeAnimation 会使用一个 NSArray 保存这些数值 。

6.2.2.CABasicAnimation 可看做是只有2个关键帧的 CAKeyframeAnimation 。

6.3.常用属性:


values 上述的NSArray对象。里面的元素称为”关键帧” ( keyframe )。动画对象会在指定的时间( duration )内,依次显示 values 数组中的每一个关键帧。
path 可以设置一个 CGPathRef、 CGMutablePathRef ,让图层按照路径轨迹移动。path 只对 CALayer 的 anchorPoint 和position 起作用。如果设置了 path,那么 values 将被忽略。
keyTimes 可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes 中的每一个时间值都对应values中的每一帧。如果没有设置 keyTimes ,各个关键帧的时间是平分的。
1
2
3
4
5
6
7
8
9
10
11
/***晃动动画***/
//实例化关键帧动画
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath: @"transform.rotation" ];
[anim setDuration:0.5f];
//晃动角度
CGFloat angel = M_PI_4 / 12.0;
[anim setValues:@[@(angel), @(-angel), @(angel)]];
//设置循环晃动
[anim setRepeatCount:HUGE_VALF];
//将动画添加到图层
[ self .layer addAnimation:anim forKey: nil ];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/***离散点平移动画***/
// 1. 实例化关键帧动画
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath: @"position" ];
// 2. 设置关键帧动画属性
NSValue *p1 = [ NSValue valueWithCGPoint: self .center];
NSValue *p2 = [ NSValue valueWithCGPoint:CGPointMake(0, 0)];
NSValue *p3 = [ NSValue valueWithCGPoint:point];
[anim setValues:@[p1, p2, p3]];
[anim setDuration:1.0f];
//设置键值记录目标位置,以便动画结束后,修正位置
[anim setValue: @"translationTo" forKey: @"animationType" ];
[anim setValue:p3 forKey: @"targetPoint" ];
//设置代理
[anim setDelegate: self ];
// 3. 将动画添加到图层
[ self .layer addAnimation:anim forKey: nil ];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/***路径平移动画***/
// 1. 实例化关键帧动画
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath: @"position" ];
[anim setDuration:duration];
// 2. 按照矩形移动,需要使用到路径
// 1) 创建路径
CGMutablePathRef path = CGPathCreateMutable();
// 2) 设置路径内容
// 起点,宽、高
CGFloat w = to.x - self .center.x;
CGFloat h = to.y - self .center.y;
CGRect rect = CGRectMake( self .center.x, self .center.y, w, h);
CGPathAddRect(path, nil , rect);
// 3) 将路径添加到动画
[anim setPath:path];
// 4) 释放路径
CGPathRelease(path);
// 3. 将动画添加到图层
[ self .layer addAnimation:anim forKey: nil ];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/***贝塞尔曲线(一个控制点)动画***/
// 1. 实例化关键帧动画
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath: @"position" ];
[anim setDuration:duration];
// 2. 设置路径
// 中间的控制点使用屏幕上得随机点
CGPoint cp = [ self randomPoint];
CGMutablePathRef path = CGPathCreateMutable();
// 设置起始点
CGPathMoveToPoint(path, NULL , self .center.x, self .center.y);
// 添加带一个控制点的贝塞尔曲线
CGPathAddQuadCurveToPoint(path, NULL , cp.x, cp.y, to.x, to.y);
[anim setPath:path];
CGPathRelease(path);
// 设置键值记录目标位置,以便动画结束后,修正位置
[anim setValue: @"translationTo" forKey: @"animationType" ];
[anim setValue:[ NSValue valueWithCGPoint:to] forKey: @"targetPoint" ];
[anim setDelegate: self ];
// 3. 将动画添加到图层
[ self .layer addAnimation:anim forKey: nil ];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/***贝塞尔曲线(两个控制点)动画***/
// 1. 实例化关键帧动画
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath: @"position" ];
// 2. 设置路径
[anim setDuration:duration];
// 中间的控制点使用屏幕上得随机点
CGPoint cp1 = [ self randomPoint];
CGPoint cp2 = [ self randomPoint];
CGMutablePathRef path = CGPathCreateMutable();
// 设置起始点
CGPathMoveToPoint(path, NULL , self .center.x, self .center.y);
// 添加带一个控制点的贝塞尔曲线
CGPathAddCurveToPoint(path, NULL , cp1.x, cp1.y, cp2.x, cp2.y, to.x, to.y);
[anim setPath:path];
CGPathRelease(path);
// 设置键值记录目标位置,以便动画结束后,修正位置
[anim setValue: @"translationTo" forKey: @"animationType" ];
[anim setValue:[ NSValue valueWithCGPoint:to] forKey: @"targetPoint" ];
[anim setDelegate: self ];
// 3. 将动画添加到图层
[ self .layer addAnimation:anim forKey: nil ];
1
2
3
4
5
6
7
8
9
10
/***动画代理方法***/
- ( void )animationDidStop:(CAAnimation *)anim finished:( BOOL )flag
{
     // 取出动画类型
     NSString *type = [anim valueForKey: @"animationType" ];
     if ([type isEqualToString: @"translationTo" ]) {
         // 取出目标点,并设置self.center
         self .center = [[anim valueForKey: @"targetPoint" ]CGPointValue];
     }
}

6.4.CAKeyframeAnimation 计算模式属性 (calculationMode)

6.4.1.所谓计算模式:其主要针对的是每一帧的内容为一个坐标点的情况,也就是对 anchorPoint 和 position 进行的动画。

6.4.2.当在平面坐标系中有多个离散的点的时候,可以是离散的,也可以直线相连后进行插值计算,也可以使用圆滑的曲线将他们相连后进行插值计算。

6.4.3.calculationMode目前提供如下几种模式:


kCAAnimationLinear 默认值,表示当关键帧为座标点的时候,关键帧之间直接直线相连进行插值计算
kCAAnimationDiscrete 离散的,不进行插值计算,所有关键帧直接逐个进行显示
kCAAnimationPaced 使得动画均匀进行,而不是按 keyTimes 设置的或者按关键帧平分时间,此时 keyTimes 和 timingFunctions 无效
kCAAnimationCubic 对关键帧为座标点的关键帧进行圆滑曲线相连后插值计算,这里的主要目的是使得运行的轨迹变得圆滑
kCAAnimationCubicPaced 在 kCAAnimationCubic 的基础上使得动画运行变得均匀,就是系统时间内运动的距离相同,此时 keyTimes 以及 timingFunctions 也是无效的。

6.4.4.此属性研究的优先级不高,只有再做复杂动画,同时动画效果不理想的时候,才需要考虑使用这一属性。

7.CAAnimationGroup

7.1.CAAnimationGroup,是CAAnimation的子类,可以保存一组动画对象,将CAAnimationGroup对象加入层后,组中所有动画对象可以同时并发运行。

7.2.属性说明:


animations 用来保存一组动画对象的 NSArray

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/***动画组***/
// 1. 实例化动画组
CAAnimationGroup *group = [[CAAnimationGroup alloc]init];
CFTimeInterval duration = 2.0;
// 2. 定义动画组中的动画
CAKeyframeAnimation *move = [AnimationView moveWithDuration:duration from: self .myView.center to:location controlPointCount:4];
CABasicAnimation *rotation = [AnimationView rotationWithDuration:duration from:0.0 to:2 * M_PI];
CABasicAnimation *scale = [AnimationView scaleWithDuration:duration from:2.0 to:0.5];
CABasicAnimation *opacity = [AnimationView opacityWithDuration:duration from:0.1 to:1.0];
// 3. 将定义的动画添加到动画组
[group setAnimations:@[move, rotation, scale, opacity]];
// 定义动画组执行的时间长度
[group setDuration:duration];
// 5) 设置键值记录目标位置,以便动画结束后,修正位置
// 并不是所有的动画方法都需要设置目标点
[group setValue: @"translationTo" forKey: @"animationType" ];
[group setValue:[ NSValue valueWithCGPoint:location] forKey: @"targetPoint" ];
[group setDelegate: self ];
// 4. 将动画组添加到视图的图层
[ self .myView.layer addAnimation:group forKey: nil ];
1
2
3
4
5
6
7
8
9
10
/***动画代理方法***/
- ( void )animationDidStop:(CAAnimation *)anim finished:( BOOL )flag
{
     // 取出动画类型
     NSString *type = [anim valueForKey: @"animationType" ];
     if ([type isEqualToString: @"translationTo" ]) {
         // 取出目标点,并设置self.center
         self .center = [[anim valueForKey: @"targetPoint" ]CGPointValue];
     }
}

8.CATransition

8.1.CATransition 是 CAAnimation 的子类,用于做转场动画,能够为层提供移出屏幕和移入屏幕的动画效果。 iOS 比 Mac OS X 的转场动画效果少一点。

8.2.UINavigationController 就是通过 CATransition 实现了将控制器的视图推入屏幕的动画效果。

8.3.动画属性:


type 动画过渡类型
subtype 动画过渡方向
startProgress 动画起点(在整体动画的百分比)
endProgress 动画终点(在整体动画的百分比)

8.4.转场动画过渡效果:


 类型字符串  效果说明 关键字 方向
fade 交叉淡化过渡  YES  
push 新视图把旧视图推出去  YES  
moveIn 新视图移到旧视图上面  YES  
reveal 将旧视图移开,显示下面的新视图  YES  
cube 立方体翻滚效果    
oglFlip 上下左右翻转效果    
suckEffect 收缩效果,如一块布被抽走    NO
rippleEffect 水滴效果    NO
pageCurl 向上翻页效果    
pageUnCurl 向下翻页效果    
cameraIrisHollowOpen 相机镜头打开效果    NO
cameraIrisHollowClose 相机镜头关闭效果    NO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 1. 实例化转场动画 注意不要和CATransaction(动画事务)搞混
CATransition *transition = [[CATransition alloc]init];
// 设置类型 type
[transition setType: @"moveIn" ];
// 根据轻扫方向设置子类型 subType
// 2. 判断轻扫的方向
UIImageView *imageView = (UIImageView *)recognizer.view;
if (UISwipeGestureRecognizerDirectionLeft == recognizer.direction) {
     NSLog ( @"向左" );
     [transition setSubtype:kCATransitionFromRight];
     imageView.tag = (imageView.tag + 1) % self .imageList.count;
} else {
     NSLog ( @"向右" );
     [transition setSubtype:kCATransitionFromLeft];
     // 针对负数去模,需要注意修正索引
     imageView.tag = (imageView.tag - 1 + self .imageList.count) % self .imageList.count;
}
[transition setDuration:0.5f];
[imageView setImage: self .imageList[imageView.tag]];
// 3. 动画添加到图层
[recognizer.view.layer addAnimation:transition forKey: nil ];

8.5.使用UIView动画函数实现转场动画(单视图):

1
2
3
4
5
6
7
8
/*
  * duration:动画的持续时间
  * view:需要进行转场动画的视图
  * options:转场动画的类型
  * animations:将改变视图属性的代码放在这个block中
  * completion:动画结束后,会自动调用这个block
  */
+ ( void )transitionWithView:(UIView *)view duration:( NSTimeInterval )duration options:(UIViewAnimationOptions)options animations:( void (^)( void ))animations completion:( void (^)( BOOL finished))completion;
1
2
3
4
5
6
7
8
/***单视图(翻转转场动画)***/
[UIView transitionWithView: self .imageView duration:1.0f options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
     // 在此设置视图反转之后显示的内容
     self .imageView.tag = ( self .imageView.tag + 1) % self .imageList.count;
     [ self .imageView setImage: self .imageList[ self .imageView.tag]];
} completion:^( BOOL finished) {
     NSLog ( @"翻转完成" );
}];

8.6.使用 UIView 动画函数实现转场动画(双视图):

1
2
3
4
5
6
7
/*
  * duration:动画的持续时间
  * options:转场动画的类型
  * animations:将改变视图属性的代码放在这个block中
  * completion:动画结束后,会自动调用这个block
  */
+ ( void )transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:( NSTimeInterval )duration options:(UIViewAnimationOptions)options completion:( void (^)( BOOL finished))completion;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/***双视图***/
// 在双视图转场时,我们可以根据是否有父视图,来判断谁进谁出
UIView *fromView = nil ;
UIView *toView = nil ;
if ( self .subView1.superview == nil ) {
     // 说明subView1要转入
     toView = self .subView1;
     fromView = self .subView2;
} else {
     // 说明subView2要转入
     toView = self .subView2;
     fromView = self .subView1;
}
[UIView transitionFromView:fromView toView:toView duration:1.0f options:UIViewAnimationOptionTransitionFlipFromTop completion:^( BOOL finished) {
     NSLog ( @"转场完成" );
     // 每次转场后,会调整参与转场视图的父视图,因此,参与转场视图的属性,需要是强引用
     // 转场之后,入场的视图会有两个强引用,一个是视图控制器,另一个是视图
     NSLog ( @"subView1's superView: %@" , self .subView1.superview);
     NSLog ( @"subView2's superView: %@" , self .subView2.superview);
}];

8.6.1.使用双视图转场动画时,需要掌握视图的 superView 属性的变化。

8.6.2.方法调用完毕后,相当于执行了下面两句代码:

1
2
3
4
// 添加toView到父视图
[fromView.superview addSubview:toView];
// 把fromView从父视图中移除
[fromView.superview removeFromSuperview];

8.7.转场动画存在的问题是动画过程中无法交互,如果要在切换时实现交互效果需要使用 UIScrollView + UIPageControl 。

9.UIActivityIndicatorView

9.1.UIActivityIndicatorView 是一个旋转进度轮,可以用来告知用户有一个操作正在进行中,一般用initWithActivityIndicatorStyle 初始化。

9.2.相关方法:


- (void)startAnimating;  开始动画
- (void)stopAnimating;  停止动画
- (BOOL)isAnimating;  是否正在运行动画

9.3.属性数值:


UIActivityIndicatorViewStyleWhiteLarge 大型白色指示器
UIActivityIndicatorViewStyleWhite 标准尺寸白色指示器
UIActivityIndicatorViewStyleGray 灰色指示器,用于白色背景

9.3.常用第三方框架 SVProgressHUB

9.3.1.常用显示方法:showWithStatus ; showWithStatus:maskType:

9.3.2.关闭方法:dismiss

9.3.3.SVProgressHUB 对 UIActivityIndicatorView 进行了封装,增加了文字、图像以及容器视图等属性,通过类方法调用,使用简单。

9.3.4.使用 SVProgressHUDMaskTypeGradient 等属性显示提示信息时,可以使用 NSTimer 模拟等待后台响应效果。

10.UIImageView 的序列帧动画

10.1.UIImageView可以让一系列的图片在特定的时间内按顺序显示。

10.2.属性说明:


animationImages 要显示的一组图片序列
animationDuration 完整地显示所有图片所需的时间
animationRepeatCount 动画的执行次数(默认为0,代表无限循环)

10.3.相关方法:


- (void)startAnimating;  开始动画
- (void)stopAnimating;  停止动画
- (BOOL)isAnimating;  是否正在运行动画

11.CADisplayLink

11.1.CADisplayLink 是一种以屏幕刷新频率触发的时钟机制,每秒钟执行大约60次左右。

11.2.CADisplayLink 是一个计时器,可以使绘图代码与视图的刷新频率保持同步,而 NSTimer 无法确保计时器实际被触发的准确时间。

11.3.使用方法:

11.3.1.定义 CADisplayLink 并制定触发调用方法

11.3.2.将显示链接添加到主运行循环队列

1
2
3
4
5
// 实例化游戏时钟
// 1. 实例化游戏时钟,并添加监听方法
self .gameTimer = [CADisplayLink displayLinkWithTarget: self selector: @selector (step)];
// 2. 添加到主运行循环,否则监听方法不会被触发
[ self .gameTimer addToRunLoop:[ NSRunLoop mainRunLoop] forMode: NSDefaultRunLoopMode ];

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值