一、核心动画结构及定义
Code Animation 中文翻译为核心动画,它是一组非常强的的动画处理API,是以它能做出非常炫丽的动画效果,且往往事半功倍
核心动画所处的位置入下图所示:
可以看到,Code Animation位于UIKit的下一层,是作用在CALayer(Core Animation layer)上,相较于UIView动画,它可以实现更复杂的动画效果。
下边我们看一下,核心动画的几个类及结构
下边分析一下上图结构:
**1. CAMediaTiming** 协议中定义了时间,速度,重复次数等。属性定义如下:
beginTime -> 用来设置动画延时,若想延迟1秒,就设置为CACurrentMediaTime()+1,其中CACurrentMediaTime()为图层当前时间。
duration -> 动画的持续时间。
speed -> 动画速率,决定动画时间的倍率。当speed为2时,动画时间为设置的duration的1/2。
timeOffset -> 动画时间偏移量。比如设置动画时长为3秒,当设置timeOffset为1.5时,当前动画会从中间位置开始,并在到达指定位置时,走完之前跳过的前半段动画。
repeatCount -> 动画的重复次数。
repeatDuration -> 动画的重复时间。
autoreverses -> 动画由初始值到最终值后,是否反过来回到初始值的动画。如果设置为YES,就意味着动画完成后会以动画的形式回到初始值。
fillMode -> 决定当前对象在非动画时间段的行为.比如动画开始之前,动画结束之后。
(注:其实不只是CAAnimation遵循CAMediaTiming协议,熟悉底层结构的小伙伴们应该知道CALayer也遵循这个协议,所有在一定程度上我们可以通过控制layer本身的协议属性来控制动画节奏。)
**2. CAAnimation** 核心动画基础类,不能直接使用。除了CAMediaTiming协议中的方法,增加了CAAnimationDelegate的代理属性等。具体如下:
timingFunction -> 控制动画的节奏。系统提供的包括:kCAMediaTimingFunctionLinear (匀速),kCAMediaTimingFunctionEaseIn (慢进快出),kCAMediaTimingFunctionEaseOut (快进慢出),kCAMediaTimingFunctionEaseInEaseOut (慢进慢出,中间加速),kCAMediaTimingFunctionDefault (默认),当然也可通过自定义创建CAMediaTimingFunction。
delegate -> 代理。
removedOnCompletion -> 是否让图层保持显示动画执行后的状态,默认为YES,也就是动画执行完毕后从涂层上移除,恢复到执行前的状态,如果设置为NO,并且设置fillMode为kCAFillModeForwards,则保持动画执行后的状态。
**3. CATransition** 转场动画,系统提供了很多酷炫效果。属性如下:
type -> 转场动画类型。
subtype -> 转场动画方向。
startProgress -> 动画起点进度(整体的百分比)。
endProgress -> 动画终点进度(整体的百分比)。
filter -> 自定义转场。
**4.CAPropertyAnimation** 属性动画,针对对象的可动画属性进行效果的设置,不可直接使用。添加属性具体如下:
keyPath -> CALayer的某个属性名,并通过这个属性的值进行修改,达到相应的动画效果。
additive -> 属性动画是否以当前动画效果为基础,默认为NO。
cumulative -> 指定动画是否为累加效果,默认为NO。
valueFunction -> 此属性配合CALayer的transform属性使用。
**5.CABasicAnimation**基础动画,通过keyPath对应属性进行控制,需要设置fromValue以及toValue。添加属性如下:
fromValue -> keyPath相应属性的初始值。
toValue -> keyPath相应属性的结束值。
byValue -> 在不设置toValue时,toValue = fromValue + byValue,也就是在当前的位置上增加多少。
**6.CASpringAnimation** 带有初始速度以及阻尼指数等物理参数的属性动画。我们可以把它看成在不绝对光滑的地面上,一个弹簧拴着别小球,那么我们可以这么理解他的属性(物理知识请问一下牛顿大叔):
mass -> 小球质量,影响惯性。
stiffness -> 弹簧的劲度系数。
damping -> 阻尼系数,地面的摩擦力。
initialVelocity -> 初始速度,相当于给小球一个初始速度(可正可负,方向不同)
settlingDuration -> 结算时间,根据上述参数计算出的预计时间,相对于你设置的时间,这个时间比较准确。
**7.CAKeyframeAnimation** 关键帧动画,同样通过keyPath对应属性进行控制,但它可以通过values或者path进行多个阶段的控制。属性如下:
values -> 关键帧组成的数组,动画会依次显示其中的每一帧。
path -> 关键帧路径,动画进行的要素,优先级比values高,但是只对CALayer的anchorPoint和position起作用。
keyTimes -> 每一帧对应的时间,如果不设置,则各关键帧平分设定时间。
timingFunctions -> 每一帧对应的动画节奏。
calculationMode -> 动画的计算模式,系统提供了对应的几种模式。
tensionValues -> 动画张力控制。
continuityValues -> 动画连续性控制。
biasValues -> 动画偏差率控制。
rotationMode -> 动画沿路径旋转方式,系统提供了两种模式。
**8.CAAnimationGroup** 动画组,方便对于多动画的统一控制管理。
animations -> 所有动画效果元素的数组。
二 、方法与代码示例
**1、CABasicAnimation**
在一般的应用开发中,基础动画可以满足大部分的开发需求,主要完成对于对象指定动画属性两个Value之间的动画过度。
+(instancetype)animationWithKeyPath:(nullable NSString *)path;
**path:**CALayer的某个属性名,并通过这个属性的值进行修改,达到相应的动画效果。下为可选参数:
> CATransform3D Key Paths :
> 旋转
> transform.rotation.z
> rotation.x
> rotation.y
> rotation.z
> rotation
>
> 缩放
> scale.x
> scale.y
> scale.z
> scale
>
> 平移
> translation.x
> translation.y
> translation.z
> translation
>
> 位置
> CGPoint Key Paths:position.x
> x
> y
>
> 位置及大小
> CGRect Key Paths :
> bounds.size.width
> origin.x
> origin.y
> origin
> size.width
> size.height
> size
>
> opacity 透明度
> backgroundColor 背景色
> cornerRadius 圆角
> borderWidth 边距线宽
> contents 内容
>
> 阴影
> Shadow Key Path:
> shadowColor
> shadowOffset
> shadowOpacity
> shadowRadius
代码示例:
> -(void)basicAnimationWithTag:(NSInteger)tag{
> CABasicAnimation *basicAni = nil;
> switch (tag) {
> case 0:
> //初始化动画并设置keyPath
> basicAni = [CABasicAnimation animationWithKeyPath:@"position"];
> //到达位置
> basicAni.byValue = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
> break;
> case 1:
> basicAni = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
> //到达缩放
> basicAni.toValue = @(0.1f);
> break;
> case 2:
> basicAni = [CABasicAnimation animationWithKeyPath:@"opacity"];
> basicAni.toValue=@(0.1f);
> break;
> case 3:
> basicAni = [CABasicAnimation animationWithKeyPath:@"transform"];
> //3D
> basicAni.toValue=[NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_2+M_PI_4, 1, 1, 0)];
> break;
> case 4:
> basicAni = [CABasicAnimation animationWithKeyPath:@"cornerRadius"];
> //圆角
> basicAni.toValue=@(50);
> break;
> default:
> break;
> }
> //设置代理
> basicAni.delegate = self;
> //延时执行
> //basicAni.beginTime = CACurrentMediaTime() + 2;
> //动画时间
> basicAni.duration = 1;
> //动画节奏
> basicAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
> //动画速率
> //basicAni.speed = 0.1;
> //图层是否显示执行后的动画执行后的位置以及状态
> //basicAni.removedOnCompletion = NO;
> //basicAni.fillMode = kCAFillModeForwards;
> //动画完成后是否以动画形式回到初始值
> basicAni.autoreverses = YES;
> //动画时间偏移
> //basicAni.timeOffset = 0.5;
> //添加动画
> NSString *key = NSStringFromSelector(_cmd);
> NSLog(@"动画的key ======= %@",key);
> [_animationLayer addAnimation:basicAni forKey:key];
> }
**2、CASpringAnimation**
CASpringAnimation是iOS9才引入的动画类,效果类似于UIView的spring动画,不过比其增加了质量,劲度系数等属性的扩展,继承于CABaseAnimation,用法也很简单:
> CASpringAnimation *springAni = [CASpringAnimation animationWithKeyPath:@"position"];
> springAni.damping = 2;
> springAni.stiffness = 50;
> springAni.mass = 1;
> springAni.initialVelocity = 2;
> springAni.toValue = [NSValue valueWithCGPoint:CGPointMake(270, 350)];
> springAni.duration = springAni.settlingDuration;
> [_animationLayer addAnimation:springAni forKey:@"springAnimation"];
**3.CAKeyframeAnimation**
关键帧动画和CABasicAnimation一样是CApropertyAnimation的子类,但是CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue),而CAKeyframeAnimation使用values数组可以通过(keyTimes)设置多个关键帧,同时可以利用path可以进行位置或者锚点的动画操作。代码如下
通过values设置
> CAKeyframeAnimation *keyFrameAni = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
> keyFrameAni.duration = 2;
> keyFrameAni.values = @[@(-(6) / 180.0*M_PI),@((6) / 180.0*M_PI),@(-(5) / 180.0*M_PI),@((5) / 180.0*M_PI),@(-(4) / 180.0*M_PI),@((4) / 180.0*M_PI),@(-(4) / 180.0*M_PI)];
> keyFrameAni.keyTimes = @[ @(0), @(0.225), @(0.425), @(0.6), @(0.75), @(0.875), @(1)];
> keyFrameAni.repeatCount = 2;
> [_animationLayer addAnimation:keyFrameAni forKey:@"keyFrameAnimation"];
通过path设置
CAKeyframeAnimation *keyFrameAni = [CAKeyframeAnimation animationWithKeyPath:@"position"];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:_animationLayer.position;
[path addCurveToPoint:CGPointMake(300, 500) controlPoint1:CGPointMake(100, 400) controlPoint2:CGPointMake(270, 460)];
keyFrameAni.path = path.CGPath;
keyFrameAni.duration = 1;
[_animationLayer addAnimation:keyFrameAni forKey:@"keyFrameAnimation"];
**4.CATransition**
转场动画是一种显示样式向另一种显示样式过渡的效果,能制作出酷炫的效果,不过谨慎使用私有API,防止被拒的悲剧。
> **type的enum值如下:**
> kCATransitionFade 渐变
> kCATransitionMoveIn 覆盖
> kCATransitionPush 推出
> kCATransitionReveal 揭开
还有一些私有动画类型,效果很炫酷,不过不推荐使用。
subtype可取值:
> **subtype的enum值如下:**
> kCATransitionFromRight 从右边
> kCATransitionFromLeft 从左边
> kCATransitionFromTop 从顶部
> kCATransitionFromBottom 从底部
代码示例
> CATransition *transtion = [CATransition animation];
> transtion.duration = 1;
> transtion.type = @"cube";
> transtion.subtype = kCATransitionFromRight;//kCATransitionFromLeft kCATransitionFromRight
> _animationLayer.backgroundColor = [UIColor yellowColor].CGColor;
> [_animationLayer addAnimation:transtion forKey:@"transtion"];
**5.CAAnimationGroup**
CAAnimationGroup 是一个动画组,使用Group可以将多个动画合并一起加入到层中,Group中所有动画并发执行,可以方便地实现需要多种类型动画的场景。
代码示例
//弹动动画
CAKeyframeAnimation *keyFrameAni = [CAKeyframeAnimation animationWithKeyPath:@"position.y"];
CGFloat ty = _animationLayer.position.y;
keyFrameAni.values = @[@(ty - 100),@(ty),@(ty - 50),@(ty)];
//每一个动画可以单独设置时间和重复次数,在动画组的时间基础上,控制单动画的效果
keyFrameAni.duration = 0.3;
keyFrameAni.repeatCount= MAXFLOAT;
keyFrameAni.delegate = self;
//
//圆角动画
CABasicAnimation *basicAni = [CABasicAnimation animationWithKeyPath:@"cornerRadius"];
//到达位置
basicAni.byValue = @(_animationLayer.bounds.size.width/2);
//
basicAni.duration = 1;
basicAni.repeatCount = 1;
//
basicAni.removedOnCompletion = NO;
basicAni.fillMode = kCAFillModeForwards;
//设置代理
basicAni.delegate = self;
//动画时间
basicAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
CAAnimationGroup *aniGroup = [CAAnimationGroup animation];
aniGroup.animations = @[keyFrameAni,basicAni];
aniGroup.autoreverses = YES;
//动画的表现时间和重复次数由动画组设置的决定
aniGroup.duration = 3;
aniGroup.repeatCount=MAXFLOAT;
//
[_animationLayer addAnimation:aniGroup forKey:@"groupAnimation"];
三、动画的暂停、恢复、加快及移除动画
1、speed属性是指当前层动画的速率。用于将父时间缩放到本地时间,例如。
如果速率为2,则本地时间的进展速度是父时间的两倍。
我们可以通过设置speed =0来暂停动画:
代码示例:
//获取当前layer的动画媒体时间
CFTimeInterval interval = [_animationLayer convertTime:CACurrentMediaTime() toLayer:nil];
//设置时间偏移量,保证停留在当前位置
_animationLayer.timeOffset= interval;
//暂定动画
_animationLayer.speed = 0;
设置speed =1来恢复动画
代码示例:
//获取暂停的时间
CFTimeInterval beginTime = CACurrentMediaTime() - _animationLayer.timeOffset;
//设置偏移量
_animationLayer.timeOffset = 0;
//设置开始时间
_animationLayer.beginTime= beginTime;
//开始动画
_animationLayer.speed = 1;
设置speed >1来加速动画
代码示例:
_animationLayer.speed = 2;
2、动画结束,我们可以移除动画
[_animationLayer removeAllAnimations];//移除当前层所有动画
//[_animationLayer removeAnimationForKey:@"groupAnimation"];//移除当前层上名称是groupAnimation的动画
关于Code Animation ,就写到这里了,附demo一份GitHub - Tony-iOS-Personal/AnimationDemo: 关于动画的总结demo