1. Model Layer Tree(模型层树)和Presentation Layer Tree(表示层树)
CALayer是动画产生的地方。当我们动画添加到Layer时,是不直接修改layer的属性的。所以CoreAnimation有两个layer层次结构:model layer tree(模型层树)和presentation layer tree(表示层树)。Model Layer Tree的Layers是我们直接看到layers的状态,Presentation Layer Tree的Layers是动画正在表现的值的近似。
我们可以这样来调用:
1 //模型层树 2 CALayer.modelLayer(CALayer) 3 //表示层树 4 CALayer.presentationLayer(CALayer)
例如,我们运行一个动画改变position.x的值,让Layer由左向右运动(如下图)。
我们发现在运动结束后,Layer会还原回原来的值。这是因为在默认情况下,动画在运行结束后,不会修改其Presentation Layer,也就是说,结束时会彻底移除Presentation Layer。通俗的来说,运行结束时Presentation Layer会回到Model Layer的值。
如果想动画运行结束后还保留其结束后的值,则有下面两种方法可以修改。
1)通过结束后的值来设置Layer的位置(推荐这种,因为这种方法使得动画完全可选)
1 //移动动画position 2 func addLayerAnimationPosition(layer: CALayer) { 3 let animation = CABasicAnimation(keyPath: "position") 4 animation.fromValue = NSValue(CGPoint: layer.position) 5 //移动到的位置 6 animation.toValue = NSValue(CGPoint: CGPointMake(120, 200)) 7 animation.duration = 3 8 9 layer.addAnimation(animation, forKey: "addLayerAnimationPosition") 10 11 //设置Layer结束后的位置 12 layer.position = CGPointMake(120, 200) 13 }
2)通过kCAFillModeForward和removedOnCompletion防止结束时被移除
1 //移动动画position 2 func addLayerAnimationPosition(layer: CALayer) { 3 let animation = CABasicAnimation(keyPath: "position") 4 animation.fromValue = NSValue(CGPoint: layer.position) 5 //移动到的位置 6 animation.toValue = NSValue(CGPoint: CGPointMake(120, 200)) 7 animation.duration = 3 8 //运动后的位置保持不变 9 animation.removedOnCompletion = false 10 animation.fillMode = kCAFillModeForwards 11 12 layer.addAnimation(animation, forKey: "addLayerAnimationPosition") 13 }
我们可以看到,从上面的方法可以得到动画结束后不变,但是请注意的一点是这样会造成额外的开销,因为渲染器回去进行额外的绘画工作。
2.动画的beginTime与被复制性
动画当被添加到Layer时,Layer会复制这份动画。这使我们在多个view中重用同一个动画非常有用。比如我们创建一个Layer的动画由左向右运动,当运动完成时在过1秒钟,此Layer会变透明。
1 //----------先由左向右运动,然后边透明----------- 2 //添加由左向右的动画 3 let ani = CABasicAnimation.init(keyPath: "position.x") 4 ani.toValue = 200 5 ani.duration = 3 6 ani.removedOnCompletion = false 7 ani.fillMode = kCAFillModeForwards 8 calayer.addAnimation(ani, forKey: "position_x") 9 10 //上面的动画执行时,已经被layer copy一份了,所以要想改变animation的值不会影响其动画效果 11 //重用上面的动画,当运动完成后+3秒,执行下一动画——变透明 12 ani.keyPath = "opacity" 13 ani.beginTime = CACurrentMediaTime() + 3 14 ani.toValue = 0 15 calayer.addAnimation(ani, forKey: "opacity")
如果想了解动画与bezier曲线与layer的结合,可以看CAShapeLayer、UIBezierPath与Animation的结合