Core Animation总结

Core Animation

众所周知,绚丽动画效果是iOS系统的一大特色,经过UIView层封装的动画,基本能够知足咱们应用开发的全部需求,但若须要更加自由的控制动画的展现,咱们就须要使用CoreAnimation框架中的一些类与方法spring

Core Animation基础知识

Core Animation是iOS和OS X上图形渲染和动画的基础结构,可用于为视图和应用程序的其余可视元素设置动画。Core Animation的实现逻辑是将大部分实际绘图工做交给专用图形硬件加速渲染,以实现高帧率和流畅的动画,而不会给CPU带来负担并下降应用程序的速度。数组

下图描述了CoreAnimation与UIKit框架的关系微信

Core Animation开发动画的本质就是将CALayer中的内容转化为位图从而供硬件操做,因此想熟练掌握动画操做必须了解CALayer框架

CALayer

CALayer跟UIView概念上很类似,一样都是被层级管理树管理的一些矩形块,一样能够包含内容,管理子图层,能够作动画和变换。可是最大的不一样是UIView能够处理用户的交互,而CALayer是不可以响应事件的,即便它提供了一些判断触点是否在图层范围内的方法。每个UIView视图内部都封装了一个CALayer图层,咱们经过UIView的layer属性访问这个图层。其实对于UIView来讲负责内容展现的就是它内部的CALayer,UIView只不过是将自身的展现任务交给了内部的CALayer完成,而它还肩负着一些其它的任务,好比说用户的交互响应,提供一些Core Animation底层方法的高级接口等。函数

那为何不把这些任务放在一个类中处理而是把他们做为平行关系同时存在呢?很重要的缘由是要将职责分离,这样能够避免不少重复的代码,因为iOS平台和MacOS平台上用户的交互方式有着本质的不一样,在iOS系统中咱们使用的是UIKit和UIView,而在MacOS系统中咱们使用的是AppKit和NSView,因此在这种状况下将展现部分分离出来会给苹果的多平台系统开发带来便捷。动画

@interface CALayer : NSObject <NSSecureCoding, CAMediaTiming>
{
@private
  struct _CALayerIvars {
    int32_t refcount;
    uint32_t magic;
    void *layer;
#if TARGET_OS_MAC && !TARGET_RT_64_BIT
    void * _Nonnull unused1[8];
#endif
  } _attr;
}

CALayer属性:CALayer层的主要工做是管理您提供的视觉内容,图层自己具备可设置的可视属性,例如背景颜色,边框和阴影。除了管理视觉内容以外,还保留有关其内容的几何形状的信息(例如其位置,大小和变换),用于在屏幕上呈现该内容。ui

Core Animation

接下来咱们将讲解下Core Animation的CAAnimation、CAPropertyAnimation、CABasicAnimation、CAKeyframeAnimation、CASpringAnimation、CATransition、CAAnimationGroup及他们之间的关系,其间也穿插了CALayer动画运行的原理、Animation-KeyPath值、CATransaction事务类、检测动画的结束、暂停和恢复图层的动画等内容url

CAAnimation

CAAnimation是核心动画的基类,不能直接使用,主要负责动画的时间、速度等,自己实现了CAMediaTiming协议。spa

@interface CAAnimation : NSObject
    <NSSecureCoding, NSCopying, CAMediaTiming, CAAction>
{
@private
  void *_attr;
  uint32_t _flags;
}
CAAnimation属性 说明
timingFunction CAMediaTimingFunction速度控制函数,控制动画运行的节奏
removedOnCompletion 默认为YES,表明动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。若是想让图层保持显示动画执行后的状态,那就设置为NO,不过还要设置fillMode为kCAFillModeForwards
delegate 代理(animationDidStart、animationDidStop)

ps:CAMediaTimingFunction介绍代理

kCAMediaTimingFunctionLinear(线性):匀速,给你一个相对静态的感受
kCAMediaTimingFunctionEaseIn(渐进):动画缓慢进入,而后加速离开
kCAMediaTimingFunctionEaseOut(渐出):动画全速进入,而后减速的到达目的地
kCAMediaTimingFunctionEaseInEaseOut(渐进渐出):动画缓慢的进入,中间加速,而后减速的到达目的地。这个是默认的动画行为。

CAMediaTiming协议

duration,beginTime、repeatCount、speed、timeOffset、repeatDuration、autoreverses这些时间相关的属性都在这个类中。协议中的这些属性经过一些方式结合在一块儿,准确的控制着时间。

CAMediaTiming属性 说明
beginTime 指定动画开始的时间。从开始延迟几秒的话,设置为【CACurrentMediaTime() + 秒数】 的方式
duration 动画的时长
speed 动画运行速度(若是把动画的duration设置为3秒,而speed设置为2,动画将会在1.5秒结束,由于它以两倍速在执行)
timeOffset 结合一个暂停动画(speed=0)一块儿使用来控制动画的“当前时间”。暂停的动画将会在第一帧卡住,而后经过改变timeOffset来随意控制动画进程
repeatCount 重复的次数。不停重复设置为 HUGE_VALF
repeatDuration 设置动画的时间。在该时间内动画一直执行,不计次数。
autoreverses 动画结束时是否执行逆动画,若是duration为1s,则完成一次autoreverse就须要2s。
fillMode CAMediaTimingFillMode枚举

ps:CAMediaTimingFillMode介绍

kCAFillModeRemoved:这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到以前的状态
kCAFillModeForwards:当动画结束后,layer会一直保持着toValue的状态
kCAFillModeBackwards:若是要让动画在开始以前(延迟的这段时间内)显示fromValue的状态
kCAFillModeBoth:这个其实就是上面两个的合成.动画加入后开始以前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态

注意必须配合animation.removeOnCompletion = NO才能达到以上效果

CAPropertyAnimation

继承自CAAnimation,不能直接使用,要想建立动画对象,应该使用它的两个子类:CABasicAnimation和CAKeyframeAnimation

You do not create instances of CAPropertyAnimation: to animate the properties of a Core Animation layer, create instance of the concrete subclasses CABasicAnimation or CAKeyframeAnimation.
CAPropertyAnimation属性 说明
keyPath 经过指定CALayer的一个属性名称为keyPath(NSString类型),而且对CALayer的这个属性的值进行修改,达到相应的动画效果。好比,指定@“position”为keyPath,就修改CALayer的position属性的值,以达到平移的动画效果

CABasicAnimation

CABasicAnimation是核心动画类簇中的一个类,其父类是CAPropertyAnimation,其子类是CASpringAnimation,它的祖父是CAAnimation。它主要用于制做比较单一的动画,例如,平移、缩放、旋转、颜色渐变、边框的值的变化等,也就是将layer的某个属性值从一个值到另外一个值的变化

CABasicAnimation属性 说明
fromValue 所改变属性的起始值
toValue 所改变属性的结束时的值
byValue 所改变属性相同起始值的改变量

代码以下

let baseAnim = CABasicAnimation(keyPath: "position")
        baseAnim.duration = 2;
        //开始的位置
        baseAnim.fromValue = NSValue(cgPoint: (imgView?.layer.position)!)
        baseAnim.toValue = NSValue(cgPoint: CGPoint(x: 260, y: 260))
//        baseAnim.isRemovedOnCompletion = false
//        baseAnim.fillMode = CAMediaTimingFillMode.forwards
        imgView?.layer.add(baseAnim, forKey: "baseAnim-position")
        imgView?.center = CGPoint(x: 260, y: 260)

防止动画结束后回到初始状态

如上面代码所示,须要添加imgView?.center = CGPoint(x: 260, y: 260)来防止防止动画结束后回到初始状态,网上还有另一种方法是 设置removedOnCompletion、fillMode两个属性

baseAnim.removedOnCompletion = NO;
baseAnim.fillMode = kCAFillModeForwards;

可是这种方法会形成modelLayer没有修改,_view1的实际坐标点并无在所看到的位置,会产生一些问题

CALayer动画运行的原理

CALayer有两个实例方法presentationLayer(简称P)和modelLayer(简称M),

/* presentationLayer
 * 返回一个layer的拷贝,若是有任何活动动画时,包含当前状态的全部layer属性
 * 其实是逼近当前状态的近似值。
 * 尝试以任何方式修改返回的结果都是未定义的。
 * 返回值的sublayers 、mask、superlayer是当前layer的这些属性的presentationLayer
 */

- (nullable instancetype)presentationLayer;

/* modelLayer
 * 对presentationLayer调用,返回当前模型值。
 * 对非presentationLayer调用,返回自己。
 * 在生成表示层的事务完成后调用此方法的结果未定义。
 */

- (instancetype)modelLayer;

从中能够看到P便是咱们看到的屏幕上展现的状态,而M就是咱们设置完当即生效的真实状态;打一个比方的话,P是个瞎子,只负责走路(绘制内容),而M是个瘸子,只负责看路(如何绘制)

CALayer动画运行的原理:P会在每次屏幕刷新时更新状态,当有动画CAAnimation(简称A)加入时,P由动画A控制进行绘制,当动画A结束被移除时P则再去取M的状态展现。可是因为M没有变化,因此动画执行结束又会回到起点。若是想要P在动画结束后就停在当前状态而不回到M的状态,咱们就须要给A设置两个属性,一个是A.removedOnCompletion = NO;表示动画结束后A依然影响着P,另外一个是A.fillMode = kCAFillModeForwards,这两行代码将会让A控制住P在动画结束后保持不变,可是此时咱们的P和M不一样步,咱们看到的P是toValue的状态,而M则仍是本身原来的状态。举个栗子,咱们初始化一个view,它的状态为1,咱们给它的layer加个动画,from是0,to是2,设置fillMode为kCAFillModeForewards,则动画结束后P的状态是2,M的状态是1,这可能会致使一些问题出现。好比你点P所在的位置点不动,由于响应点击的是M。因此咱们应该让P和M同步,如上代码imgView?.center = CGPoint(x: 260, y: 260)须要提一点的是:对M赋值,不会影响P的显示,当P想要显示的时候,它已经被A控制了,并不会先闪现一下。

Animation-KeyPath值

上面的动画的KeyPath值咱们只使用了position,其实还有不少类型能够设置,下面咱们列出了一些比较经常使用的

keyPath值 说明 值类型
position 移动位置 CGPoint
opacity 透明度 0-1
bounds 变大与位置 CGRect
bounds.size 由小变大 CGSize
backgroundColor 背景颜色 CGColor
cornerRadius 渐变圆角 任意数值
borderWidth 改变边框border的大小((图形周围边框,border默认为黑色)) 任意数值
contents 改变layer内容(图片)注意若是想要达到改变内容的动画效果;首先在运行动画以前定义好layer的contents contents CGImage
transform.scale 缩放、放大 0.0-1.0
transform.rotation.x 旋转动画(翻转,沿着X轴) M_PI*n
transform.rotation.Y 旋转动画(翻转,沿着Y轴) M_PI*n
transform.rotation.Z 旋转动画(翻转,沿着Z轴) M_PI*n
transform.translation.x 旋转动画(翻转,沿着X轴) 任意数值
transform.translation.y 旋转动画(翻转,沿着Y轴) 任意数值

CAKeyframeAnimation

CABasicAnimation是将属性从起始值更改成结束值,而CAKeyframeAnimation对象是容许你以线性或非线性的方式设置一组目标值的动画。关键帧动画由一组目标数据值和每一个值到达的时间组成。不但能够简单的只指定值数组和时间数组,还能够按照路径进行更改图层的位置。动画对象采用您指定的关键帧,并经过在给定时间段内从一个值插值到下一个值来构建动画。

CAKeyframeAnimation属性 说明
values 关键帧值表示动画必须执行的值,此属性中的值仅在path属性的值为nil时才使用。根据属性的类型,您可能须要用NSValue对象的NSNumber包装这个数组中的值。对于一些核心图形数据类型,您可能还须要将它们转换为id,而后再将它们添加到数组中。将给定的关键帧值应用于该层的时间取决于动画时间,由calculationMode、keyTimes和timingFunctions属性控制。关键帧之间的值是使用插值建立的,除非将计算模式设置为kcaanimation离散
path 基于点的属性的路径,对于包含CGPoint数据类型的层属性,您分配给该属性的路径对象定义了该属性在动画长度上的值。若是指定此属性的值,则忽略值属性中的任何数据
keyTimes keyTimes的值与values中的值一一对应指定关键帧在动画中的时间点,取值范围为[0,1]。当keyTimes没有设置的时候,各个关键帧的时间是平分的
timingFunctions 一个可选的CAMediaTimingFunction对象数组,指定每一个关键帧之间的动画缓冲效果
calculationMode 关键帧间插值计算模式
rotationMode 定义沿路径动画的对象是否旋转以匹配路径切线

ps:

timingFunctions:动画缓冲效果

kCAMediaTimingFunctionLinear:线性起搏,使动画在其持续时间内均匀地发生
kCAMediaTimingFunctionEaseIn:使一个动画开始缓慢,而后加速,随着它的进程
kCAMediaTimingFunctionEaseOut:使动画快速开始,而后缓慢地进行
kCAMediaTimingFunctionEaseInEaseOut:使动画开始缓慢,在其持续时间的中间加速,而后在完成以前再放慢速度
kCAMediaTimingFunctionDefault:默认,确保动画的时间与大多数系统动画的匹配

calculationMode:动画计算方式

kCAAnimationLinear:默认差值
kCAAnimationDiscrete:逐帧显示
kCAAnimationPaced:匀速 无视keyTimes和timingFunctions设置
kCAAnimationCubic:keyValue之间曲线平滑 可用 tensionValues,continuityValues,biasValues 调整
kCAAnimationCubicPaced:keyValue之间平滑差值 无视keyTimes

rotationMode:旋转方式

kCAAnimationRotateAuto:自动
kCAAnimationRotateAutoReverse:自动翻转 不设置则不旋转

代码一、用values属性

//建立动画对象
        let keyAnim = CAKeyframeAnimation(keyPath: "position")
        //设置values
        keyAnim.values = [NSValue(cgPoint: CGPoint(x: 100, y: 200)),
                          NSValue(cgPoint: CGPoint(x: 200, y: 200)),
                          NSValue(cgPoint: CGPoint(x: 200, y: 300)),
                          NSValue(cgPoint: CGPoint(x: 100, y: 300)),
                          NSValue(cgPoint: CGPoint(x: 100, y: 400)),
                          NSValue(cgPoint: CGPoint(x: 200, y: 500))]
        //重复次数 默认为1
        keyAnim.repeatCount = MAXFLOAT
        //设置是否原路返回 默认为false
        keyAnim.autoreverses = true
        //设置移动速度,越小越快
        keyAnim.duration = 4.0

        keyAnim.isRemovedOnCompletion = false
        keyAnim.fillMode = .forwards

        keyAnim.timingFunctions = [CAMediaTimingFunction(name: .easeInEaseOut)]

        imgView?.layer.add(keyAnim, forKey: "keyAnim-Values")

代码二、用path属性

//建立动画对象
        let keyAnim = CAKeyframeAnimation(keyPath: "position")

        //建立一个CGPathRef对象,就是动画的路线
        let path = CGMutablePath()
        //自动沿着弧度移动
        path.addEllipse(in: CGRect(x: 150, y: 200, width: 200, height: 100))
        //设置开始位置
        path.move(to: CGPoint(x: 100, y: 100))
        //沿着直线移动
        path.addLine(to: CGPoint(x: 200, y: 100))
        path.addLine(to: CGPoint(x: 200, y: 200))
        path.addLine(to: CGPoint(x: 100, y: 200))
        path.addLine(to: CGPoint(x: 100, y: 300))
        path.addLine(to: CGPoint(x: 200, y: 400))

        //沿着曲线移动
        path.addCurve(to: CGPoint(x: 50.0, y: 275.0), control1: CGPoint(x: 150.0, y: 275.0), control2: CGPoint(x: 70.0, y: 120.0))
        path.addCurve(to: CGPoint(x: 150.0, y: 275.0), control1: CGPoint(x: 250.0, y: 275.0), control2: CGPoint(x: 90.0, y: 120.0))
        path.addCurve(to: CGPoint(x: 250.0, y: 275.0), control1: CGPoint(x: 350.0, y: 275.0), control2: CGPoint(x: 110, y: 120.0))
        path.addCurve(to: CGPoint(x: 350.0, y: 275.0), control1: CGPoint(x: 450.0, y: 275.0), control2: CGPoint(x: 130, y: 120.0))

        keyAnim.path = path
        //重复次数 默认为1
        keyAnim.repeatCount = MAXFLOAT
        //设置是否原路返回 默认为false
        keyAnim.autoreverses = true
        //设置移动速度,越小越快
        keyAnim.duration = 4.0

        keyAnim.isRemovedOnCompletion = false
        keyAnim.fillMode = .forwards

        keyAnim.timingFunctions = [CAMediaTimingFunction(name: .easeInEaseOut)]

        imgView?.layer.add(keyAnim, forKey: "keyAnim-Path")

CASpringAnimation

iOS9新出的CASpringAnimation继承于CABaseAnimation,是苹果专门解决开发者关于弹簧动画的这个需求而封装的类

CASpringAnimation属性 说明
mass 质量,影响图层运动时的弹簧惯性,质量越大,弹簧拉伸和压缩的幅度越大,默认值:1
stiffness 刚度系数(劲度系数/弹性系数),刚度系数越大,形变产生的力就越大,运动越快。默认值: 100
damping 阻尼系数,阻止弹簧伸缩的系数,阻尼系数越大,中止越快。默认值:10;
initialVelocity 初始速率,动画视图的初始速度大小。默认值:0;速率为正数时,速度方向与运动方向一致,速率为负数时,速度方向与运动方向相反;
settlingDuration 估算时间 返回弹簧动画到中止时的估算时间,根据当前的动画参数估算;

代码以下

let springAnim = CASpringAnimation(keyPath: "bounds")

        springAnim.toValue = NSValue(cgRect:CGRect(x: 200, y: 230, width: 140, height: 140))

        //mass模拟的是质量,影响图层运动时的弹簧惯性,质量越大,弹簧拉伸和压缩的幅度越大 默认值:1
        springAnim.mass = 5
        //stiffness刚度系数(劲度系数/弹性系数),刚度系数越大,形变产生的力就越大,运动越快。默认值: 100
        springAnim.stiffness = 80
        //damping阻尼系数,阻止弹簧伸缩的系数,阻尼系数越大,中止越快。默认值:10;
        springAnim.damping = 8
    //initialVelocity初始速率,动画视图的初始速度大小。默认值:0;速率为正数时,速度方向与运动方向一致,速率为负数时,速度方向与运动方向相反;
        springAnim.initialVelocity = 10
        //估算时间 返回弹簧动画到中止时的估算时间,根据当前的动画参数估算;
        springAnim.duration = springAnim.settlingDuration

        imgView?.layer.add(springAnim, forKey: "springAnim")

CATransition

CATransition是CAAnimation的子类,用于作转场动画,可以为图层提供移出屏幕和移入屏幕的动画效果。

CATransition属性 说明
type CATransitionType,动画过渡类型
subtype CATransitionSubtype,动画移动方向
startProgress 动画起点(在总体动画的百分比)
endProgress 动画终点(在总体动画的百分比)

ps:若是不须要动画执行整个过程(动画执行到中间部分就中止),能够指定startProgress,endProgress属性。

CATransitionType:动画过渡类型

kCATransitionFade:渐变
kCATransitionMoveIn:覆盖
kCATransitionPush:推出
kCATransitionReveal:揭开

除此以外,还支持如下私有方法

cube:立方体旋转
suckEffect:吮吸
oglFlip:翻转
rippleEffect:水波动画
pageCurl:翻页
pageUnCurl:反翻页
cemeraIrisHollowOpen:开镜头
cameraIrisHollowClose:关镜头

CATransitionSubtype:控制动画方向,上/下/左/右 4个不一样方向的动画

kCATransitionFromRight
kCATransitionFromLeft
kCATransitionFromTop
kCATransitionFromBottom

CAAnimationGroup

单一的动画并不能知足某些特定需求,这时就须要用到CAAnimationGroup,其是CAAnimation的子类,默认状况下,一组动画对象是同时运行的,也能够经过设置动画对象的beginTime属性来更改动画的时间

CATransition属性 说明
animations [CAAnimation],动画组

代码以下

let groupAnim = CAAnimationGroup()

        //建立keyAnim
        let keyAnim = CAKeyframeAnimation(keyPath: "position")
        //设置values
        keyAnim.values = [NSValue(cgPoint: CGPoint(x: 100, y: 200)),
                          NSValue(cgPoint: CGPoint(x: 200, y: 200)),
                          NSValue(cgPoint: CGPoint(x: 200, y: 300)),
                          NSValue(cgPoint: CGPoint(x: 100, y: 300)),
                          NSValue(cgPoint: CGPoint(x: 100, y: 400)),
                          NSValue(cgPoint: CGPoint(x: 200, y: 500))]
        keyAnim.duration = 4.0

        keyAnim.timingFunctions = [CAMediaTimingFunction(name: .easeInEaseOut)]

        //建立渐变圆角
        let animation = CABasicAnimation(keyPath: "cornerRadius")
        animation.toValue = 40
        animation.duration = 4.0
        imgView?.layer.masksToBounds = true

        groupAnim.animations = [keyAnim, animation]
        groupAnim.duration = 4.0
        groupAnim.repeatCount = MAXFLOAT
        groupAnim.autoreverses = true

        imgView?.layer.add(groupAnim, forKey: "groupAnim")

将动画分组在一块儿的更高级方法是使用事务对象。经过容许您建立嵌套的动画集并为每一个动画分配不一样的动画参数,事务提供了更大的灵活性。

CATransaction事务类

CATransaction事务类能够对多个layer的属性同时进行修改,它分隐式事务,和显式事务。 当咱们向图层添加显式或隐式动画时,Core Animation都会自动建立隐式事务。可是,咱们还能够建立显式事务以更精确地管理这些动画。

  • 区分隐式动画和隐式事务:隐式动画经过隐式事务实现动画 。
  • 区分显式动画和显式事务:显式动画有多种实现方式,显式事务是一种实现显式动画的方式。
  • 除显式事务外,任何对于CALayer属性的修改,都是隐式事务.

隐式事务

//建立layer
let layer = CALayer()
layer.bounds = CGRect(x: 0, y: 0, width: 100, height: 100)
layer.position = CGPoint(x: 100, y: 350)
layer.backgroundColor = UIColor.red.cgColor
layer.borderColor = UIColor.black.cgColor
layer.opacity = 1.0
view.layer.addSublayer(layer)

//触发动画

// 设置变化动画过程是否显示,默认为true不显示
CATransaction.setDisableActions(false)
layer.cornerRadius = (layer.cornerRadius == 0.0) ? 30.0 : 0.0
layer.opacity = (layer.opacity == 1.0) ? 0.5 : 1.0

显式事务:经过明确的调用begin,commit来提交动画

CATransaction.begin()
layer.zPosition = 200.0
layer.opacity = 0.0
CATransaction.commit()

使用事务的主要缘由之一是在显式事务的范围内,咱们能够更改持续时间,计时功能和其余参数。还能够为整个事务分配完成块,以便在动画组完成时通知应用。

例如,将动画的默认持续时间更改成8秒,使用setValue:forKey:方法进行修改,目前支持的属性包括: "animationDuration", "animationTimingFunction","completionBlock", "disableActions".

CATransaction.begin()
CATransaction.setValue(8.0, forKey: "animationDuration")
//执行动画
CATransaction.commit()

嵌套事务: 当咱们要为不一样动画集提供不一样默认值的状况下可使用嵌套事务。要将一个事务嵌套在另外一个事务中,只需再次调用begin,且每一个begin调用必须一一对应一个commit方法。只有在为最外层事务提交更改后,Core Animation才会开始关联的动画。

嵌套显式事务代码

//事务嵌套
CATransaction.begin()   // 外部transaction
CATransaction.setValue(2.0, forKey: "animationDuration")
layer.position = CGPoint(x: 140, y: 140)

CATransaction.begin()   // 内部transaction
CATransaction.setValue(5.0, forKey: "animationDuration")
layer.zPosition = 200.0
layer.opacity = 0.0

CATransaction.commit()  // 内部transaction
CATransaction.commit()  // 外部transaction

检测动画的结束

核心动画支持检测动画开始或结束的时间。这些通知是进行与动画相关的任何内务处理任务的好时机。例如,您可使用开始通知来设置一些相关的状态信息,并使用相应的结束通知来拆除该状态。

有两种不一样的方式能够通知动画的状态:

  • 使用setCompletionBlock:方法将完成块添加到当前事务。当事务中的全部动画完成后,事务将执行完成块。
  • 将委托分配给CAAnimation对象并实现animationDidStart:animationDidStop:finished:委托方法。

若是要让两个动画连接在一块儿,以便在另外一个完成时启动,请不要使用动画通知。而是使用动画对象的beginTime属性按照所需的时间启动每一个动画对象。将两个动画连接在一块儿,只需将第二个动画的开始时间设置为第一个动画的结束时间。

每一个图层都有本身的本地时间,用于管理动画计时。一般,两个不一样层的本地时间足够接近,您能够为每一个层指定相同的时间值,用户可能不会注意到任何内容。可是因为superLayer或其自己Layer的时序参数设置,层的本地时间会发生变化。例如,更改Layer的speed属性会致使该Layer(及其子Layer)上的动画持续时间按比例更改。

为了确保Layer的时间值合适,CALayer类定义了convertTime:fromLayer:convertTime:toLayer:方法。咱们可使用这些方法将固定时间值转换为Layer的本地时间或将时间值从一个Layer转换为另外一个Layer。这些方法可能影响图层本地时间的媒体计时属性,并返回可与其余图层一块儿使用的值。

可以使用下面示例来获取图层的当前本地时间。CACurrentMediaTime函数返回计算机的当前时钟时间,该方法将本机时间并转换为图层的本地时间。

获取图层的当前本地时间

CFTimeInterval localLayerTime = [myLayer convertTime:CACurrentMediaTime()fromLayer:nil];

在图层的本地时间中有时间值后,可使用该值更新动画对象或图层的与时序相关的属性。使用这些计时属性,您能够实现一些有趣的动画行为,包括:

  • beginTime属性设置动画的开始时间。一般动画开始下一个周期的时候,咱们可使用beginTime将动画开始时间延迟几秒钟。将两个动画连接在一块儿的方法是将一个动画的开始时间设置为与另外一个动画的结束时间相匹配。若是延迟动画的开始,则可能还须要将fillMode属性设置为kCAFillModeBackwards。即便图层树中的图层对象包含不一样的值,此填充模式也会使图层显示动画的起始值。若是没有此填充模式,您将看到在动画开始执行以前跳转到最终值。其余填充模式也可用。
  • autoreverses属性使动画在指定时间内执行,而后返回到动画的起始值。咱们能够将autoreverses与repeatCount组合使用,就能够起始值和结束值之间来回动画。将重复计数设置为自动回转动画的整数(例如1.0)会致使动画中止在其起始值上。添加额外的半步(例如重复计数为1.5)会致使动画中止在其结束值上。 使用timeOffset具备组动画的属性能够在稍后的时间启动某些动画。

暂停和恢复图层的动画

- (void)pauseLayer:(CALayer *)layer {
   CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime()fromLayer:nil];
   layer.speed = 0.0;
   layer.timeOffset = pausedTime;
}

- (void)resumeLayer:(CALayer *)layer {
   CFTimeInterval pausedTime = [layer timeOffset];
   layer.speed = 1.0;
   layer.timeOffset = 0.0;
   layer.beginTime = 0.0;
   CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime()fromLayer:nil]  -  pausedTime;
   layer.beginTime = timeSincePause;
}
iOSSir公众号技术交流微信群!
须要进群能够添加公众号助理“kele22558!”
公众号助理
相关文章
相关标签/搜索