iOS UIView動畫實踐(五):Keyframe Animation

前言

有些時候你們可能會遇到製做複雜、具備連貫性UIView動畫的需求,這時你們可能會使用在completion閉包中銜接一段一段的動畫,使之成爲一段連續的動畫。閉包

若是咱們只是鏈接2個,或者3個動畫,這種方式或許還行得通,但若是有更多的動畫片斷須要鏈接的時候,這種方式會帶來災難性的問題,你的代碼會很是的冗餘,不斷的在completion閉包中嵌套代碼,使代碼維護起來至關的困難。因此今天向你們介紹能更好地實現這個需求的方法,Keyframe動畫。app

Keyframe動畫可讓咱們有效的拆分由若干段動畫鏈接而成的複雜動畫,能夠較爲精準的定義每段動畫的起始點及持續時間,而且在代碼組織方面也很是清晰。先看看今天要帶你們實現的動畫Demo:動畫

           

使用場景

咱們先來認識一下,在什麼樣的場景下須要使用Keyframe動畫。如圖下所示,這是一個由四段動畫組成的一個複雜動畫,讓UIView沿着長方形的軌跡運動:spa

咱們來看看用代碼如何實現:.net

[cpp] view plaincopyrest

  1. UIView.animateWithDuration(1, animations: {  code

  2.     view.center.x += 200.0  orm

  3. }, completion: { _ in  ip

  4.     UIView.animateWithDuration(1, animations: {  文檔

  5.         view.center.y += 100.0  

  6.     }, completion: { _ in  

  7.         UIView.animateWithDuration(1, animations: {  

  8.             view.center.x -= 200.0  

  9.         }, completion: { _ in  

  10.             UIView.animateWithDuration(1, animations: {  

  11.                 view.center.y -= 100.0  

  12.             }, completion: nil)  

  13.         })  

  14.     })  

  15. })  

經過上面的僞代碼能夠看到,咱們使用了completion閉包的方式鏈接每一段的動畫,代碼看起來尚且算清晰,可讀性也馬馬虎虎。可是你們想象一下,若是咱們使UIView按照一個複雜的路線運行,這一段動畫可能有十幾、幾十段動畫組成的,那麼若是再使用completion閉包這種方式鏈接,那代碼是多麼的慘不忍睹。幸虧咱們有Keyframe動畫,下面就讓咱們來看看如何使用Keyframe動畫。

Keyframe動畫

首先咱們會使用到UIView的另外一個動畫方法animateKeyframesWithDuration(_: delay: options: animations: completion: ) 

[cpp] view plaincopy

  1. UIView.animateKeyframesWithDuration(2, delay: 0, options: [], animations: {  

  2.     // add keyframes  

  3. }, completion: nil)  

這個方法的幾個參數與前幾個使用過的動畫方法參數同樣。上面代碼片斷的意思是整個關鍵幀動畫的持續時間爲2秒、無延遲、無動畫選項、執行完畢後無後續執行的代碼。

注:該方法的動畫選項再也不是UIViewAnimationOptions,而是UIViewKeyframeAnimationOptions。具體的內容你們能夠去查閱Apple的文檔。

接下來咱們要在animations閉包中添加關鍵幀了:

[cpp] view plaincopy

  1. UIView.animateKeyframesWithDuration(2, delay: 0, options: [], animations: {  

  2.     UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0.25, animations: {  

  3.         view.center.x += 200.0  

  4.     })  

  5. }, completion: nil)  

addKeyframeWithRelativeStartTime(_: relativeDuration: animations: )是UIView添加關鍵幀的方法,該方法有三個參數:

  • startTime:關鍵幀開始時間,該時間是相對整個關鍵幀動畫持續時間的相對時間,通常值在0到1之間。若是爲0,則代表這一關鍵幀從整個動畫的第0秒開始執行,若是設爲0.5,則代表從整個動畫的中間開始執行。

  • relativeDuration:關鍵幀持續時間,該時間一樣是相對整個關鍵幀動畫持續時間的相對時間,通常值也在0到1之間。若是設爲0.25,則代表這一關鍵幀的持續時間爲整個動畫持續時間的四分之一。

  • animations:設置視圖動畫屬性的動畫閉包。

咱們解釋一下上面這段代碼。整個關鍵幀動畫的持續時間爲2秒,第一個關鍵幀從第0秒開始,運行0.5秒結束。下面咱們完成其餘三個關鍵幀:

[cpp] view plaincopy

  1. UIView.animateKeyframesWithDuration(2, delay: 0, options: [], animations: {  

  2.     UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0.25, animations: {  

  3.         view.center.x += 200.0  

  4.     })  

  5.     UIView.addKeyframeWithRelativeStartTime(0.25, relativeDuration: 0.25, animations: {  

  6.         view.center.y += 100.0  

  7.     })  

  8.     UIView.addKeyframeWithRelativeStartTime(0.5, relativeDuration: 0.25, animations: {  

  9.         view.center.x -= 200.0  

  10.     })  

  11.     UIView.addKeyframeWithRelativeStartTime(0.75, relativeDuration: 0.25, animations: {  

  12.         view.center.y -= 100.0  

  13.     })  

  14. }, completion: nil)  

第二個關鍵幀的開始時間爲0.25,也就是從整個動畫時間的第0.5時開始執行,一樣持續0.5秒。後兩個關鍵幀的參數就不難理解了。

如今整個代碼看起來很是整潔,條理清晰,可讀性很是好,並且能夠有更精確的控制。即便再多幾個關鍵幀也一樣能夠從容應對。

關鍵幀動畫不只僅用於同一個視圖的分段動畫,也可以使使用於不一樣視圖的組合動畫,因爲咱們還沒講到圖層動畫,因此,開篇的示例動畫中就使用了關鍵幀動畫實現了多個視圖的組合動畫。

示例動畫

在這個示例中雖然看起來是一個紙飛機視圖的連續動畫,但實際上是由三個紙飛機視圖組合而成的:

從圖中能夠看到實際上是有三個紙飛機視圖,只不過在界面加載以前2號和3號紙飛機視圖的透明度都是爲零。

整個動畫是由這三個紙飛機視圖經過關鍵幀動畫組合而成:

圖中標示出了三個飛機視圖的運行軌跡、視圖大小、視圖透明度的狀態,咱們來看看代碼如何實現:

[cpp] view plaincopy

  1. let zoomInScaleTransform = CGAffineTransformMakeScale(0.2, 0.2)  

  2. UIView.animateKeyframesWithDuration(3, delay: 0, options: [], animations: {  

  3.     UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0.2, animations: {  

  4.         self.customHeaderView.paperAirplane.center.x += self.view.frame.width  

  5.         self.customHeaderView.paperAirplane.center.y += -180  

  6.         self.customHeaderView.paperAirplane.transform = zoomInScaleTransform  

  7.     })  

  8.     UIView.addKeyframeWithRelativeStartTime(0.3, relativeDuration: 0.01, animations: {  

  9.         self.customHeaderView.paperAirplaneOpposite.alpha = 1  

  10.         self.customHeaderView.paperAirplaneOpposite.transform = zoomInScaleTransform  

  11.     })  

  12.     UIView.addKeyframeWithRelativeStartTime(0.3, relativeDuration: 0.5, animations: {  

  13.         self.customHeaderView.paperAirplaneOpposite.transform = CGAffineTransformIdentity  

  14.         self.customHeaderView.paperAirplaneOpposite.center.x -= self.view.frame.width  

  15.         self.customHeaderView.paperAirplaneOpposite.center.y += 90  

  16.     })  

  17.     UIView.addKeyframeWithRelativeStartTime(0.9, relativeDuration: 0.01, animations: {  

  18.         self.customHeaderView.paperAirplaneComeBack.alpha = 1  

  19.     })  

  20.     UIView.addKeyframeWithRelativeStartTime(0.9, relativeDuration: 0.2, animations: {  

  21.         self.customHeaderView.paperAirplaneComeBack.center.x += 33  

  22.     })  

  23. }, completion: { _ in  

  24.     self.restorePaperAirplaneStatus()  

  25. })  

你們看到這你們可能會有疑問了,三段動畫怎麼會有五個關鍵幀呢,咱們來刨析一下:

  • 第一個關鍵幀:完成1號紙飛機視圖運動到右上角並移出屏幕,視圖逐漸變小的動畫。該關鍵幀從整個動畫的第0秒開始執行,持續時間爲0.6秒。

  • 第二個關鍵幀:因爲2號紙飛機視圖的初始透明度爲零,因此在第二個關鍵幀將透明度設爲1,而且縮小視圖。注意這兩個動做須要在瞬間完成,因此relativeDuration設爲0.01,一個極短的時間。開始時間爲整個動畫的第0.9秒開始,較第一個關鍵幀延遲0.3秒。

  • 第三個關鍵幀:與第二個關鍵幀同時開始執行,完成2號紙飛機視圖從小變大、而且往左下角運動,一直移出屏幕。持續時間爲1.5秒。

  • 第四個關鍵幀:與第二個關鍵幀做用類似,改變3號紙飛機視圖的透明度,一樣是在瞬間完成。

  • 第五個關鍵幀:與第四個關鍵幀同時執行, 完成向右移動的動畫,持續0.6秒。

關鍵幀完成以後,在completion閉包中調用restorePaperAirplaneStatus()方法,恢復3個紙飛機視圖的狀態及位置,以便再次執行動畫。

總結

你們在使用關鍵幀動畫時,對於關鍵幀的開始時間和持續時間須要仔細設置,保證每一個關鍵幀在合適的時間開始,執行恰當的持續時間。在必要時候也須要在關鍵幀裏修改視圖的一些狀態,但要設置極短的持續時間,表示瞬間完成。

下一篇會向你們介紹在使用Auto Layout的狀況下,如何經過約束實現動畫,好了今天就先到這裏吧。

相關文章
相關標籤/搜索