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")