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是動畫正在表現的值的近似。
我們可以這樣來調用:
//模型層樹 CALayer.modelLayer(CALayer) //表示層樹 CALayer.presentationLayer(CALayer)
例如,我們運行一個動畫改變position.x的值,讓Layer由左向右運動(如下圖)。

我們發現在運動結束後,Layer會還原回原來的值。這是因為在默認情況下,動畫在運行結束後,不會修改其Presentation Layer,也就是說,結束時會徹底移除Presentation Layer。通俗的來說,運行結束時Presentation Layer會回到Model Layer的值。
如果想動畫運行結束後還保留其結束後的值,則有下面兩種方法可以修改。
1)通過結束後的值來設置Layer的位置(推薦這種,因為這種方法使得動畫完全可選)
//移動動畫position
func addLayerAnimationPosition(layer: CALayer) {
let animation = CABasicAnimation(keyPath: "position")
animation.fromValue = NSValue(CGPoint: layer.position)
//移動到的位置
animation.toValue = NSValue(CGPoint: CGPointMake(120, 200))
animation.duration = 3
layer.addAnimation(animation, forKey: "addLayerAnimationPosition")
//設置Layer結束後的位置
layer.position = CGPointMake(120, 200)
}
2)通過kCAFillModeForward和removedOnCompletion防止結束時被移除
//移動動畫position
func addLayerAnimationPosition(layer: CALayer) {
let animation = CABasicAnimation(keyPath: "position")
animation.fromValue = NSValue(CGPoint: layer.position)
//移動到的位置
animation.toValue = NSValue(CGPoint: CGPointMake(120, 200))
animation.duration = 3
//運動後的位置保持不變
animation.removedOnCompletion = false
animation.fillMode = kCAFillModeForwards
layer.addAnimation(animation, forKey: "addLayerAnimationPosition")
}
我們可以看到,從上面的方法可以得到動畫結束後不變,但是請注意的一點是這樣會造成額外的開銷,因為渲染器回去進行額外的繪畫工作。
2.動畫的beginTime與被復制性
動畫當被添加到Layer時,Layer會復制這份動畫。這使我們在多個view中重用同一個動畫非常有用。比如我們創建一個Layer的動畫由左向右運動,當運動完成時在過1秒鐘,此Layer會變透明。
//----------先由左向右運動,然後邊透明-----------
//添加由左向右的動畫
let ani = CABasicAnimation.init(keyPath: "position.x")
ani.toValue = 200
ani.duration = 3
ani.removedOnCompletion = false
ani.fillMode = kCAFillModeForwards
calayer.addAnimation(ani, forKey: "position_x")
//上面的動畫執行時,已經被layer copy一份了,所以要想改變animation的值不會影響其動畫效果
//重用上面的動畫,當運動完成後+3秒,執行下一動畫——變透明
ani.keyPath = "opacity"
ani.beginTime = CACurrentMediaTime() + 3
ani.toValue = 0
calayer.addAnimation(ani, forKey: "opacity")