iOS动画详解

前言

Core Animation(核心动画),它是一组非常强大的跨平台的动画处理API,iOS和mac OS均可使用,使用它能做出非常炫丽的动画效果。Core Animation是直接作用在CALayer上,且都是在后台操作的,不会阻塞主线程。
因为所有的动画都是作用在Layer层,所以这篇文章在讲解动画之前先对CALayer做一个简单的介绍。

CALayer简介

CALayer包含在QuartzCore框架中,这是一个跨平台框架,可支持iOS和Mac OSX;CALayer也是整个图层类的基础,是所有核心动画图层的父类,使用CoreAnimation开发动画的本质就是将CALayer中的内容转化为位图再供硬件操作,drawRect的本质也是将图绘制到了UIView的layer中;在iOS中CALayer的设计主要是为了内容展示和动画操作,它本身并不包含在UIKit中,所以不能响应事件。

文章末有对CALayer属性及注意事项做介绍

目录

本文主要从以下几方面入手:

  • CALayer:动画主作用层
  • CAAnimation:核心动画的基础类,抽象类,不能直接使用,负责动画运行时间、速度的控制,本身实现了CAMediaTiming协议。
  • CAAnimationGroup:动画组,一种组模式设计,可以并发执行若干动画效果。
  • CAPropertyAnimation:属性动画的基类,也是个抽象类,本身不具备动画效果,只有子类才有。
  • CATransition 转场动画,界面之间跳转(切换),主要通过滤镜进行动画效果设置。
  • CABaseAnimation:基础动画,通过修改属性进行动画参数控制,只有初始状态和结束状态。
  • CAKeyFrameAnimation:关键帧动画,同样是通过属性进行动画参数控制,但与CABaseAnimation不同的是它可以有多个状态控制。
  • CASpringAnimation:弹簧动画。

他们之间层级关系如图:


iOS动画详解_第1张图片
层级关系图

>>本文涉及demo代码链接-github<<

详解

一、CAAnimation

CAAnimation是CoreAnimation框架中执行动画的基类,是个抽象类,也是所有动画对象的父类,本身不具备动画效果,必须依靠它的子类实现,主要负责控制动画的持续时间和速度。

CAAnimation中的属性详解:

CAAnimation *animation = [CAAnimation animation];
    //动画持续时间
    animation.duration = 1;
    //动画重复次数
    animation.repeatCount = 1;
    //动画重复时间
    animation.repeatDuration = 2;
    /**
     默认YES,代表动画执行完毕后就从涂层上移除,图形会恢复到动画执行前状态;
     如果想让图层保持执行后状态,则设置为NO,此外还需设置fillMode为KCAFillModeForwards
     */
    animation.removedOnCompletion = YES;
    /**
     动画延时执行时间,若想延迟2s后执行,则设置CACurrentMediaTime()+2,
     * CACurrentMediaTime():是coreAnimation的一个全局时间概念,指代图层当前时间
     */
    animation.beginTime = CACurrentMediaTime() + 2;
    /**
     决定当前对象在非active时间段的行为,比如动画开始之前,动画结束之后
     * KCAFillModeRemoved:默认值,动画开始前和结束后都对layer没任何影响,动画结束后layer会恢复到之前状态;
     * KCAFillModeForwards:当动画结束后,layer会一直保持结束后的状态;
     * KCAFillModeBackwards:在动画开始前,只要将动画加入layer,layer便会立即进入动画初始状态并等待动画开始;
     * KCAFillModeBoth:上两个的合成-动画加入layer后,layer会立即进入初始状态,动画结束后,layer会保持动画结束后状态
     */
    animation.fillMode = kCAFillModeRemoved;//默认值
    /**
     动画缓冲函数,速度函数
     * kCAMediaTimingFunctionLinear//匀速的线性计时函数
     * kCAMediaTimingFunctionEaseIn//缓慢加速,然后突然停止
     * kCAMediaTimingFunctionEaseOut//全速开始,慢慢减速
     * kCAMediaTimingFunctionEaseInEaseOut//慢慢加速再慢慢减速
     * kCAMediaTimingFunctionDefault//也是慢慢加速再慢慢减速,但是它加速减速速度略慢
     */
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    //代理
    animation.delegate = self;

在这里穿插一段话,removeOnCompletion和fillMode都有影响动画结束状态的作用,而且两者之间还存在着一定的关联关系,那么他们之间又有什么区别和联系呢?
动画执行完后恢复到执行前状态:

removedOnCompletion = YES;

动画执行完后保持执行后状态:

removedOnCompletion = NO;
fillMode = kCAFillModeForwards;//必须设置

fillMode是指动画非active时间段的行为,即开始前或结束后kCAFillModeForwards是在动画开始之layer迅速进入指定位置开始执行动画并在removedOnCompletion = NO的前提下会停在动画结束的最后位置,而kCAFillModeBackwards则是在动画开始之迅速进入指定状态并在动画开始后执行动画,动画结束后迅速返回到layer的本身位置
kCAFillModeBothkCAFillModeForwardskCAFillModeBackwards的集合,所以kCAFillModeBoth就很好理解了,如果removedOnCompletion = NO那layer会在动画开始之前就会迅速进入动画的初始位置并在执行完动画后停在动画结束的位置,如果removedOnCompletion = YESlayer会在动画开始之前就会迅速进入动画的初始位置并在执行完动画后迅速返回到layer的本身位置

CAAnimation的代理函数:

- (void)animationDidStart:(CAAnimation *)anim{
    //动画开始的时候调用
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
    //动画停止的时候调用
}

可能出现的问题:

动画结束后想停在最后位置状态而非初始化状态的解决方案

animation.removedOnCompletion = NO; 
animation.fillMode = kCAFillModeForwards; 

必须设置“removedOnCompletion”和“fillMode”这两个属性

必须要注意的点

@property(nullable, strong) id delegate;
大家也应该注意到了,动画的代理属性是strong强类型,这点一定要注意,这就意味着在使用代理函数的时候有极大风险会造成循环引用问题,所以在动画结束后下次使用前一定要将当前动画移除


二、CAPropertyAnimation

CAPropertyAnimation,父类是CAAnimation,本身也是一个抽象类,自身并不能对layer进行动画操作,需要其子类CABasicAnimation和CAKeyframeAnimation来实现动画。

属性介绍:

/* The key-path describing the property to be animated. */
//指定接收层动画的关键路径(下文有讲)
@property(nullable, copy) NSString *keyPath;

/* When true the value specified by the animation will be "added" to
 * the current presentation value of the property to produce the new
 * presentation value. The addition function is type-dependent, e.g.
 * for affine transforms the two matrices are concatenated. Defaults to
 * NO. */
//如何处理多个动画在同一时间段执行的结果,若为true,同一时间段的动画合成为一个动画,默认为false。(使用 CAKeyframeAnimation 时必须将该属性指定为 true ,否则不会出现期待的结果)
@property(getter=isAdditive) BOOL additive;

/* The `cumulative' property affects how repeating animations produce
 * their result. If true then the current value of the animation is the
 * value at the end of the previous repeat cycle, plus the value of the
 * current repeat cycle. If false, the value is simply the value
 * calculated for the current repeat cycle. Defaults to NO. */
//该属性指定动画是否为累加效果,下一次动画执行是否接着刚才的动画,默认为false
@property(getter=isCumulative) BOOL cumulative;

/* If non-nil a function that is applied to interpolated values
 * before they are set as the new presentation value of the animation's
 * target property. Defaults to nil. */
//该属性值是一个CAValueFunction对象,该对象负责对属性改变的插值计算,系统已经提供了默认的插值计算方式,因此一般无须指定该属性。
@property(nullable, strong) CAValueFunction *valueFunction;

方法介绍:

/* Creates a new animation object with its `keyPath' property set to
 * 'path'. */
//KeyPath:动画效果,值需符合规范
+ (instancetype)animationWithKeyPath:(nullable NSString *)path;
 

下面是对keypath比较全面的总结,每个keypath对应一种属性值的变化,其中涉及到颜色变化的都必须使用CGColor,因为对应是对layer的属性。

KeyPath介绍:


 /* CATransform3D Key Paths */
 /* 旋转x,y,z分别是绕x,y,z轴旋转 */
 static NSString *kCARotation = @"transform.rotation";
 static NSString *kCARotationX = @"transform.rotation.x";
 static NSString *kCARotationY = @"transform.rotation.y";
 static NSString *kCARotationZ = @"transform.rotation.z";
 
/* 缩放x,y,z分别是对x,y,z方向进行缩放 */
 static NSString *kCAScale = @"transform.scale";
 static NSString *kCAScaleX = @"transform.scale.x";
 static NSString *kCAScaleY = @"transform.scale.y";
 static NSString *kCAScaleZ = @"transform.scale.z";
 
 /* 平移x,y,z同上 */
 static NSString *kCATranslation = @"transform.translation";
 static NSString *kCATranslationX = @"transform.translation.x";
 static NSString *kCATranslationY = @"transform.translation.y";
 static NSString *kCATranslationZ = @"transform.translation.z";
 
 /* 平面 */
 /* CGPoint中心点改变位置,针对平面 */
 static NSString *kCAPosition = @"position";
 static NSString *kCAPositionX = @"position.x";
 static NSString *kCAPositionY = @"position.y";
 
 /* CGRect */
 static NSString *kCABoundsSize = @"bounds.size";
 static NSString *kCABoundsSizeW = @"bounds.size.width";
 static NSString *kCABoundsSizeH = @"bounds.size.height";
 static NSString *kCABoundsOriginX = @"bounds.origin.x";
 static NSString *kCABoundsOriginY = @"bounds.origin.y";
 
 /* 透明度 */
 static NSString *kCAOpacity = @"opacity";
 /* 背景色 */
 static NSString *kCABackgroundColor = @"backgroundColor";
 /* 圆角 */
 static NSString *kCACornerRadius = @"cornerRadius";
 /* 边框 */
 static NSString *kCABorderWidth = @"borderWidth";
 /* 阴影颜色 */
 static NSString *kCAShadowColor = @"shadowColor";
 /* 偏移量CGSize */
 static NSString *kCAShadowOffset = @"shadowOffset";
 /* 阴影透明度 */
 static NSString *kCAShadowOpacity = @"shadowOpacity";
 /* 阴影圆角 */
 static NSString *kCAShadowRadius = @"shadowRadius";
 #endif /* AnimationKeyPathName_h */

下文有对KeyPath的具体使用说明


三、CABasicAnimation

CABasicAnimation是核心动画类簇中的一个类,其父类是CAPropertyAnimation,其子类是CASpringAnimation,它的祖父是CAAnimation。它主要用于制作比较单一的动画,即不考虑中间变换过程,只考虑起点与目标变化,例如,平移、缩放、旋转、颜色渐变、边框的值的变化等,也就是将layer的某个属性值从一个值到另一个值的变化。类似x -> y这种变化,但是对于x -> y -> z甚至更多的变化是不行的。

常用属性:

//KeyPath相应属性的初始值
@property(nullable, strong) id fromValue;
//KeyPath相应属性的结束值
@property(nullable, strong) id toValue;
//KeyPath相应属性的初始值的改变值
@property(nullable, strong) id byValue;

很明显,fromvalue表示初始状态,tovalue表示最终状态,byvalue是在fromvalue的基础上发生的变化,这个可以慢慢测试,主要还是from和to。

代码实践:

旋转动画
//旋转动画
- (CABasicAnimation *)baseAnimation{
    CABasicAnimation *ani = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    //    baseAnimation.fromValue = @M_PI;
    //旋转弧度
    ani.toValue = @(M_PI * 2);
    //    baseAnimation.byValue = @M_PI_2;
    //设置动画重复次数
    ani.repeatCount = MAXFLOAT;
    //动画执行时间
    ani.duration = 1;
    return ani;
}
iOS动画详解_第2张图片
旋转
缩放动画
//缩放动画
- (CABasicAnimation *)scaleAnimation{
    CABasicAnimation *ani = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    //    scale.fromValue = @0;
    ani.toValue = @1.2;
    ani.repeatCount = MAXFLOAT;
    ani.duration = 1;
    return ani;
}
iOS动画详解_第3张图片
缩放
颜色变化
- (CABasicAnimation *)colorAnimation{
    CABasicAnimation *ani = [CABasicAnimation animationWithKeyPath:@"backgroundColor"];
    ani.toValue = CFBridgingRelease([UIColor blueColor].CGColor);
    ani.repeatCount = MAXFLOAT;
    ani.duration = 1;
    return ani;
}
圆角变化
//圆角变化
- (CABasicAnimation *)radiusAni{
    CABasicAnimation *ani = [CABasicAnimation animationWithKeyPath:@"cornerRadius"];
    ani.toValue = @25;
    ani.repeatCount = MAXFLOAT;
    ani.duration = 1;
    return ani;
}

等等,不难看出,所有的动画效果其实都只是针对KeyPath值的实现,此处需要特别注意的是参数fromvaluetovaluebyvalue都是id类型,在给这些参数赋值的时候一定要注意,值一定是Object类型的,对于一些非Object类型的值可以用@强制转换一下


四、CAKeyFrameAnimation

关键帧动画,CApropertyAnimation的子类,,也是通过属性定义动画类型,其通过一组动画类型的值(或者一个指定的路径)和这些值对应的时间节点以及各时间节点的过渡方式来控制显示的动画。关键帧动画可以通过path属性和values属性来设置动画的关键帧。
它与CABaseAnimation的不同在于后者只局限于始末状态,但前者可以定义多个状态,让你的动画更灵活。

属性解析:

/**
就是上述的NSArray对象。
里面的元素称为”关键帧”(keyframe)。
动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧
起点必须为values的第一个值。*/
@property(nullable, copy) NSArray *values;

/**
作用与values属性一样,同样是用于指定整个动画所经过的路径的。
需要**注意**的是,values与path是互斥的,
当values与path同时指定时,path会覆盖values。
path只对CALayer的anchorPoint和position起作用。
如果你设置了path,那么values将被忽略*/
@property(nullable) CGPathRef path;

/**
该属性是一个数组,用于指定每个子路径的时间,
可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,
keyTimes中的每一个时间值都对应values中的每一帧.
当keyTimes没有设置的时候,各个关键帧的时间是平分的。
如果指定值,则首尾必须为0和1*/
@property(nullable, copy) NSArray *keyTimes;

/**
这个属性用以指定时间函数,类似于运动的加速度,有以下几种类型
* kCAMediaTimingFunctionLinear//线性
* kCAMediaTimingFunctionEaseIn//淡入
* kCAMediaTimingFunctionEaseOut//淡出
* kCAMediaTimingFunctionEaseInEaseOut//淡入淡出
* kCAMediaTimingFunctionDefault//默认

注意:这是一个数组,你有几个子路径就应该传入几个元素*/
@property(nullable, copy) NSArray *timingFunctions;

/**
calculationMode 规定了关键帧之间的值如何计算,是控制关键帧动画时间的另一种方法。
 * kCAAnimationLinear:默认值,线性过渡,快速回转到初始状态
 * kCAAnimationDiscrete:离散运动,从一个帧直接跳跃到另一个帧,注意是直接跳跃,无过渡
 * kCAAnimationPaced:向被驱动的方向施加一个恒定的力,以恒定速度运动,此时keyTimes和timingFunctions无效
 * kCAAnimationCubic:对关键帧为座标点的关键帧进行圆滑曲线相连后插值计算,是使得运行的轨迹变得圆滑

 * kCAAnimationCubicPaced:在kCAAnimationCubic的基础上使得动画运行变得均匀,就是系统时间内运动的距离相同,此时keyTimes以及timingFunctions也是无效的
*/
@property(copy) CAAnimationCalculationMode calculationMode;

/**
 对于具有三次计算模式的动画,这些属性提供对插值方案的控制。 每个关键帧可能具有与之关联的张力,连续性和偏差值,每个都在[-1,1]范围内(这定义了Kochanek-Bartels样条,请参阅http://en.wikipedia.org/wiki/Kochanek-Bartels_spline)。 
// 张力值控制曲线的“紧密度”(正值更紧,负值更圆)。 连续性值控制段的连接方式(正值给出尖角,负值给出倒角)。 偏差值定义曲线发生的位置(正值在控制点之前移动曲线,负值在控制点之后移动它)。 
//每个数组中的第一个值定义第一个控制点的切线的行为,第二个值控制第二个点的切线,依此类推。 任何未指定的值都默认为零(如果未指定所有值,则给出Catmull-Rom样条曲线)。
*/
/**
动画的张力,当动画为立方计算模式的时候此属性提供了控制插值,
因为每个关键帧都可能有张力所以连续性会有所偏差它的范围为[-1,1]*/
@property(nullable, copy) NSArray *tensionValues;
/**
动画的连续性值*/
@property(nullable, copy) NSArray *continuityValues;
/**
动画的偏斜率*/
@property(nullable, copy) NSArray *biasValues;

/* Defines whether or objects animating along paths rotate to match the
 * path tangent. Possible values are `auto' and `autoReverse'. Defaults
 * to nil. The effect of setting this property to a non-nil value when
 * no path object is supplied is undefined. `autoReverse' rotates to
 * match the tangent plus 180 degrees. */
/**
默认nil
它有两种可选值:
* kCAAnimationRotateAuto:自动旋转
* kCAAnimationRotateAutoReverse:自动倒转
如果这个属性设置成以上两个值中的任意一个,当前layer都会始终保持朝向运动方向,也就是跟随运动方向自动旋转
当没有设置路径的时候我们用此属性的话也是可行的
一般配合path使用*/
@property(nullable, copy) CAAnimationRotationMode rotationMode;

代码实践

因为CAKeyFrameAnimation和CABaseAnimation都是继承自CAPropertyAnimation,所以他的动画类型也是根据KeyPath来的,以下只拿position动画做的实践:
通过values属性设置的动画

//设置values的方式
- (CAAnimation *)keyFrameAnimation1{
    
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"position";
    animation.values = @[[NSValue valueWithCGPoint:CGPointMake(50, 50)],
                         [NSValue valueWithCGPoint:CGPointMake(100, 150)],
                         [NSValue valueWithCGPoint:CGPointMake(200, 50)],
                         [NSValue valueWithCGPoint:CGPointMake(300, 500)]
                         ];
    animation.keyTimes = @[@0,@0.9,@1];
    animation.duration = 2;
    animation.repeatCount = MAXFLOAT;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeBoth;
    /**
     calculationMode 规定了关键帧之间的值如何计算,是控制关键帧动画时间的另一种方法。
     * kCAAnimationLinear:默认值,线性过渡,快速回转到初始状态
     * kCAAnimationDiscrete:从一个帧直接跳跃到另一个帧,注意是直接跳跃,无过渡
     * kCAAnimationPaced:向被驱动的方向施加一个恒定的力,以恒定速度反向运动,回弹时间与duration一致
     * kCAAnimationCubic:与kCAAnimationLinear类似
     * kCAAnimationCubicPaced:与kCAAnimationPaced类似
     */
    animation.calculationMode = kCAAnimationCubicPaced;
    //设定每个帧之间的速度变化函数
    animation.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],
                                  [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];
//    animation.rotationMode = kCAAnimationRotateAuto;
    return animation;
}

通过path属性设置的动画

//设置path的方式
- (CAAnimation *)keyFrameAnimation2{
    
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"position";
    animation.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 200, 100, 100)].CGPath;
    animation.keyTimes = @[@0,@0.9,@1];
    animation.duration = 2;
    animation.repeatCount = MAXFLOAT;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    
//    animation.calculationMode = kCAAnimationCubicPaced;
    //设定每个帧之间的动画
    animation.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],
                                  [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];
    animation.rotationMode = kCAAnimationRotateAuto;
    return animation;
}

注意

  • values属性与path属性 互斥,如果二者皆有的话,path会覆盖values
  • rotationMode属性被设置后极有可能会覆盖timingFunctions的效果;
  • KeyTimes如果有值,则值一定为0开头,1结尾
  • calculationMode值为kCAAnimationPacedkCAAnimationCubicPaced时,keyTimes以及timingFunctions的设置无效;
  • path只对CALayeranchorPointposition起作用;

五、CASpringAnimation

弹性动画,iOS9才引入的动画类,它继承于CABaseAnimation

属性说明:

API_AVAILABLE(macos(10.11), ios(9.0), watchos(2.0), tvos(9.0))
@interface CASpringAnimation : CABasicAnimation

/* The mass of the object attached to the end of the spring. Must be greater
   than 0. Defaults to one. */
//质量,影响图层运动时的弹簧惯性,质量越大,弹簧拉伸和压缩的幅度越大
@property CGFloat mass;

/* The spring stiffness coefficient. Must be greater than 0.
 * Defaults to 100. */
//刚度系数(劲度系数/弹性系数),刚度系数越大,形变产生的力就越大,运动越快
@property CGFloat stiffness;

/* The damping coefficient. Must be greater than or equal to 0.
 * Defaults to 10. */
//阻尼系数,阻止弹簧伸缩的系数,阻尼系数越大,停止越快
@property CGFloat damping;

/* The initial velocity of the object attached to the spring. Defaults
 * to zero, which represents an unmoving object. Negative values
 * represent the object moving away from the spring attachment point,
 * positive values represent the object moving towards the spring
 * attachment point. */

@property CGFloat initialVelocity;

/* 初始速率,动画视图的初始速度大小 
速率为正数时,速度方向与运动方向一致,速率为负数时,速度方向与运动方向相反*/

@property(readonly) CFTimeInterval settlingDuration;

代码实践

- (CAAnimation *)springAnimation{
    CASpringAnimation *animation = [CASpringAnimation animation];
    animation.keyPath = @"position.x";
//    animation.fromValue = @100;
    animation.byValue = @50;
    //质量,影响图层运动时的弹簧惯性,质量越大,弹簧拉伸和压缩的幅度越大
    animation.mass = 2;
    //刚度系数(劲度系数/弹性系数),刚度系数越大,形变产生的力就越大,运动越快
    animation.stiffness = 300;
    //阻尼系数,阻止弹簧伸缩的系数,阻尼系数越大,停止越快
    animation.damping = 5;
    //初始速率,动画视图的初始速度大小
    //速率为正数时,速度方向与运动方向一致,速率为负数时,速度方向与运动方向相反
    animation.initialVelocity = -15;
//    animation.removedOnCompletion = NO;
    //使用估算时间作为此次动画执行时间
    animation.duration = animation.settlingDuration;
    return animation;
}

六、CATransition

转场动画

属性介绍

/**
为动画添加一个可选的滤镜。

如果指定,那么指定的filter必须同时支持x和y,否则该filter将不起作用。

默认值为nil。

如果设置了filter,那么,为layer设置的type和subtype属性将被忽略。

该属性只在iOS 5.0以及以后版本被支持。*/

@property(retain) CIFilter *filter



/* The name of the transition. Current legal transition types include
 * `fade', `moveIn', `push' and `reveal'. Defaults to `fade'. */
/**
1.kCATransitionMoveIn 新的视图把旧的视图掩盖

2.kCATransitionPush 旧的视图移走,新的视图移进来

3.kCATransitionFade 逐渐消失,相当于调整透明度,除了这没有方向,其他的都有

4.kCATransitionReveal 旧的视图移走,显示出新的视图*/
@property(copy) CATransitionType type;

/* An optional subtype for the transition. E.g. used to specify the
 * transition direction for motion-based transitions, in which case
 * the legal values are `fromLeft', `fromRight', `fromTop' and
 * `fromBottom'. */
/**
指定预定义的过渡方向。
默认为nil。
如果指定了filter,那么该属性无效。
分别表示:过渡从右边、左边、顶部、底部 开始。
kCATransitionFromRight:
kCATransitionFromLeft:
kCATransitionFromTop:
kCATransitionFromBottom:
*/
/**
以下API效果可以安全使用
cube 方块
suckEffect 三角
rippleEffect 水波抖动
pageCurl 上翻页
pageUnCurl 下翻页
oglFlip 上下翻转
cameraIrisHollowOpen 镜头快门开
cameraIrisHollowClose 镜头快门开

*/
@property(nullable, copy) CATransitionSubtype subtype;

/* The amount of progress through to the transition at which to begin
 * and end execution. Legal values are numbers in the range [0,1].
 * `endProgress' must be greater than or equal to `startProgress'.
 * Default values are 0 and 1 respectively. */

/**
定义过度的开始点
开始点的值必须小于或者等于结束点。
默认值为0.0。
如果指定了filter,那么该属性无效。
这两个属性是float类型的。
可以控制动画进行的过程,可以让动画停留在某个动画点上,值在0.0到1.0之间。endProgress要大于等于startProgress。
比如:立方体转,可以设置endProgress= 0.5,让动画停留在整个动画的特定位置(停止在旋转一般的状态)。*/
@property float startProgress;
/**
定义过渡的结束点
结束点的值必须大于或者等于开始点。
默认值为1.0。
*/
@property float endProgress;
代码实践

这是我工程中用到的一部分代码,整体格式其实就是这样的,跟其他动画一样,作用在layer层,这个动画的作用就是实现两个tableView的左右滑动效果

    [_tableView1 setHidden:YES];
    [_tableView2 setHidden:YES];
    [_tableView1 hideAnimations];
    [_tableView2 hideAnimations];
    // 根据索引执行相应操作
    switch (index) {
        case 0:
            [_tableView1 setHidden:NO];
            [_bottomView bringSubviewToFront:_tableView1];
            [self refreshTransData];
            break;
        case 1:
            [_tableView2 setHidden:NO];
            [_bottomView bringSubviewToFront:_tableView2];
            [self refreshRechargeData];
            break;
        default:
            break;
    }
    //transition
    CATransition *transition = [CATransition animation];
    transition.type = kCATransitionPush;
    transition.subtype = _selectedIndex > index ? kCATransitionFromLeft : kCATransitionFromRight;
    
    transition.duration = 0.3;
    [_bottomView.layer addAnimation:transition forKey:nil];

代码中两个tableView父试图都是bottomView

七、CAAnimationGroup

组合动画,动画组,它支持多个动画并发执行

属性说明:

这个类的属性就没有上面的多了,就一个,但它的优势和作用却是毋庸置疑的

/* An array of CAAnimation objects. Each member of the array will run
 * concurrently in the time space of the parent animation using the
 * normal rules. */

@property(nullable, copy) NSArray *animations;

优势:

  • 不需要指定属性
  • 不需要指定状态,因为CAAnimationGroup相当于多个CAAnimation动画并发执行的管理者,本身状态取决于其子动画的状态;
  • 可以播放多个属性同时变化(取决于他的子动画);
  • 可以重复嵌套

特别说明
它的animations属性,这个属性用于指定他的子动画。是一个装有CAAnimation对象的数组。这句话的重点就是因为CAAnimationGroup本身也继承于CAAnimation,所以CAAnimationGroup可以嵌套的。
下面哪个简单的实例介绍一下它的用法:

代码实践

#pragma mark - CAAnimationGroup
- (CAAnimation *)groupAnimation{
    CAAnimationGroup *group = [CAAnimationGroup animation];
    CAAnimation *a1 = [self keyFrameAnimation1];
    CAAnimation *a2 = [self translationAnimation];
    CAAnimation *a3 = [self keyFrameAnimation2];
    CAAnimation *a4 = [self springAnimation];
    group.animations = @[a1,a3,a4];
    
    NSLog(@"%f",CACurrentMediaTime());
    group.duration = a1.duration+a3.duration+a4.duration;
    a1.beginTime = .5f;
    a2.beginTime = a1.duration;
    a3.beginTime = a1.duration+a2.duration;
    a4.beginTime = group.duration-a4.duration;
    //设置动画组中所有动画的持续时间
    
    group.beginTime = CACurrentMediaTime() + 2;
    //设置动画组中所有动画运行结束后不恢复原状
    group.removedOnCompletion = NO;
    group.fillMode = kCAFillModeForwards;
    return group;
}
iOS动画详解_第4张图片
组合

案例中的所有子动画前文都有涉及,在这就不一一展示了,但有两点值得注意(可能有更多我没发现,也请大家指正):

  • 1、因为group动画是并发执行的,如果想让动画按一定顺序一一执行的话,需要手动设置beginTime属性,而且这个属性的值需要进行升序排列;
  • 2、设置beginTime属性的时候最好不要使用CACurrentTime(),否则很容易动画无效果,大家可以做个测试,去手动打印一下CACurrentTime()的值,会发现这个值非常大:
//代码
NSLog(@"%f",CACurrentMediaTime());
2018-12-28 10:54:19.615105+0800 XRAnimationDemo[807:140733] 92698.705112

大家可以看到,它打印出的数值为90000+,如果动画组中子动画beginTime设置了这个数值,基本就不动了


CALayer常用属性

CALayer分为显式动画和隐式动画,隐式动画是指只修改CALayer的属性就能形成动画效果,对属性介绍时也对这块做了描述

属性 说明 是否支持隐式动画
anchorPoint 和中心点position重合的一个点,称为“锚点”,锚点的描述是相对于x、y位置比例而言的默认在图像中心点(0.5、0.5)的位置
backgroundColor 图层背景颜色
borderColor 边框颜色
borderWidth 边框宽度
bounds 图层大小
contents 图层显示内容,layer的寄宿对象,CGImage类型
contentsScale 适合高分辨率的缩放因子
contentsRect 图层显示内容的大小和位置
cornerRadius 圆角半径
contentsCenter 图片的缩放区域,我们可以提供一个小图,并指定小图中不变的区域,其他区域根据情况进行缩放
doubleSided 图层背面是否显示,默认为YES
frame 图层大小和位置,不支持隐式动画,所以CALayer中很少使用frame,通常使用bounds和position代替
hidden 是否隐藏
mask 图层蒙版
maskToBounds 子图层是否剪切图层边界,默认为NO
opacity 透明度 ,类似于UIView的alpha
position 图层中心点位置,类似于UIView的center
shadowColor 阴影颜色
shadowOffset 阴影偏移量
shadowOpacity 阴影透明度,注意默认为0,如果设置阴影必须设置此属性
shadowPath 阴影的形状
shadowRadius 阴影模糊半径
sublayers 子图层
sublayerTransform 子图层形变
transform 图层形变

注意事项

  • 隐式属性动画的本质是这些属性的变动默认隐含了CABasicAnimation动画实现。
  • 在CALayer中很少使用frame属性,因为frame本身不支持动画效果,通常使用bounds和position代替。
  • CALayer中透明度使用opacity表示而不是alpha;中心点使用position表示而不是center。

calayer详解
calayer动画1
calayer动画2
calayer动画3

你可能感兴趣的:(iOS动画详解)