layer動畫的實現
layer動畫就是層動畫,工作原理和視圖動畫相同。在開始或者是結束時間改變la ye r的屬性值,layer相對于視圖有很多的可動畫屬性。因此layer可以提供相對多的動畫屬性選擇
一下為仿照登錄界面進行的layer動畫
為label 標題添加動畫,讓它從屏幕的外部動畫到屏幕的中央位置
*CABasicAnimation描述的是一個未知層的動畫,可以使用于所有的層,每一層就相當于運行一次它的動畫copy。用keyPath來指明動畫的屬性,position相當于當前的層相對于父層的位置 *
let flyRight = CABasicAnimation(keyPath: "position.x") flyRight.fillMode = kCAFillModeBoth//在動畫開始和結束的時候控制動畫的行為 flyRight.fromValue = -view.bounds.size.width / 2 flyRight.toValue = view.bounds.size.width / 2 flyRight.duration = 0.5 heading.layer.addAnimation(flyRight, forKey: nil)//為heading層增加一個layer動畫
注意點:fillMode默認為re moved,動畫開始就是設置的begin time 。若是沒有,標示動畫立即執行。動畫結束,layer從屏幕中移除;backwords屬性,會在屏幕上顯示動畫第一幀,知道動畫開始;forwords屬性,標示動畫結束后,會一直保留layer對象;bouth屬性混合了backwords和forwords的特點
在這個基礎上為用戶的用戶名的textfield添加一個layer動畫
注意點:由于CABasicAnimation只是一個數據模型,沒有綁定任何一個層。addAnimation會講動畫添加到層上面
代碼如下:
flyRight.beginTime = CACurrentMediaTime() + 0.3//begintime屬性設置了動畫的絕對時間,相對增加0.3s的延遲 username.layer.addAnimation(flyRight, forKey: nil)
如何處理layer在結束的時候不在指定位置的情況
補充知識點:通過debug調試代碼
通過調試,可以清楚地看到控件最終的位置
點擊登錄按鈕用layer改編背景顏色
func tintBackgroundColor(layer layer: CALayer, toColor: UIColor) { let tint = CABasicAnimation(keyPath: "backgroundColor") tint.fromValue = layer.backgroundColor tint.toValue = toColor.CGColor tint.duration = 1.0 layer.addAnimation(tint, forKey: nil) layer.backgroundColor = toColor.CGColor }
效果圖:
動畫的鍵和委托的實現
在之前做視圖動畫的時候,是不能夠暫停,停止,訪問動畫的。layer動畫可以實現對動畫的訪問,并且可以在動畫上建立一個委托對象來訪問動畫事件。和uikit動畫相比,la ye r可以在動畫開始,結束,或者在動畫的執行過程中,通過動畫委托代理做出相應的操作。那么,la ye r的怎樣理解layer的委托協議,怎樣在委托協議中檢測和控制layer動畫,鍵值配對?
動畫委托
CAAnimation以及它的子類CABasicAnimation是實現委托的,因此我們可以直接相應動畫的實現。CAAnimation并沒有特定的協議來實現動畫的委托,而是在CAAnimation的聲明文件中,對nsobjec進行擴展,增加了動畫開始和結束2個擴展方法。
用代理實現一個業務:layer動畫到達最終的位置后顯示控制臺相關信息
- 實現完成代理方法標示動畫思路: layer動畫都是滿足鍵值配對的,類似于字典,當創建好一個屬性后對它進行跟蹤。所以,為動畫模型分配一個name作為標示。對每次動畫控件的layer進行一次層的引用。
func animationDidStop(anim: CAAnimation, finished flag: Bool) { if let name = anim.valueForKey("name") as? String{ //將可變類型轉換成字符串 if name == "form" { let layer = anim.valueForKey("layer") as? CALayer//轉變成calayer的可選類型,也可能轉變失敗。 anim.setValue(nil, forKey: "layer")//當layer==nil時,應該移除動畫執行的layer。然后創建一個全新的動畫(使layer從1.25倍縮小到1倍) let pulse = CABasicAnimation (keyPath: "transform.scale") pulse.fromValue = 1.25 pulse.toValue = 1.0 pulse.duration = 0.25 layer?.addAnimation(pulse, forKey: nil)//layer為nil的話將不會添加動畫 } } }
實現一個功能業務,在控制臺上顯示一個動畫label,label逐漸顯現。當點擊任意個textfield時,label顯示到最終的位置上
核心代碼:
//label從右向左滑動的效果 let flyLeft = CABasicAnimation(keyPath: "position.x") flyLeft.fromValue = info.layer.position.x + view.frame.size.width flyLeft.toValue = info.layer.position.x flyLeft.duration = 5.0 info.layer.addAnimation(flyLeft, forKey: "infoappear")//info動畫的標示 //label淡入淡出的效果 let fadeLabelIn = CABasicAnimation(keyPath: "opacity") fadeLabelIn.fromValue = 0.2 fadeLabelIn.toValue = 1.0 fadeLabelIn.duration = 4.5 info.layer.addAnimation(fadeLabelIn, forKey: "fadein”)
點擊textfield時,讓動畫進行停止平移
extension ViewController : UITextFieldDelegate { func textFieldDidBeginEditing(textField: UITextField) { print(info.layer.animationKeys()) info.layer.removeAnimationForKey("infoappear")//移除平移的動畫 } }
設置云朵動畫的思路:為每一個云朵添加layer動畫,動畫結束之后需要重新為云朵添加動畫
每一個云朵添加layer動畫代碼:
func animateCloud(layer: CALayer) { //1 let cloudSpeed = 60.0 / Double(view.layer.frame.size.width) let duration: NSTimeInterval = Double(view.layer.frame.size.width - layer.frame.origin.x) * cloudSpeed //2 let cloudMove = CABasicAnimation(keyPath: "position.x") cloudMove.duration = duration cloudMove.toValue = self.view.bounds.size.width + layer.bounds.width/2 cloudMove.delegate = self cloudMove.setValue("cloud", forKey: "name") cloudMove.setValue(layer, forKey: "layer") layer.addAnimation(cloudMove, forKey: nil) }
//重置layer動畫代碼:
if name == "cloud" { if let layer = anim.valueForKey("layer") as? CALayer { anim.setValue(nil, forKey: "layer") layer.position.x = -layer.bounds.width/2 delay(seconds: 0.5, completion: { self.animateCloud(layer) }) } }
運行效果: