iOS 動畫-定時器動畫

林欣達發表於2016-12-10

前言

任何動畫離不開一個重要的概念——時間,CoreAnimation動畫建立後在動畫後續的不同時間點渲染了不同的影象幀,使值改變前後生成一個過渡的流暢動畫

11783864-d43992ca3fe4d1d9

定時器的作用類似於CoreAnimation的操作,在定時器啟動後對應的時間點插入回撥任務。如果每個回撥任務之間的間隔足夠短,並在每個任務之間繪製圖案,就能達成自制動畫的效果。本文分別使用NSTimerCADisplayLink兩個定時器來實現不同的動畫

關於定時器

iOS開發中有三種常見的定時器:NSTimerCADisplayLink以及GCD Timer,前兩個定時器在使用時要加入到某個執行的RunLoop當中,在每個回撥時間點會喚醒執行緒,執行任務。GCD Timer依賴於派發執行緒,從準確度上而言要強於前兩者,但是本文並不涉及這種定時器的使用。

  • NSTimer
    NSTimer是最常使用的定時器,啟動後會新增到RunLoop的定時器源中,然後在後續設定好的時間點喚醒RunLoop執行回撥。如果在回撥時間點遇到了CPU正在執行大量指令時,普遍認為該時間點的任務會被跳過,但實際效果可能與認識有偏差。在iOS10中,NSTimer還存在著不能正常釋放引用物件的bug。詳細請參考下面的文章連結
  • CADisplayLink
    CADisplayLink比較特殊,它的回撥頻率保持16.67ms一次,與螢幕的重新整理頻率一樣。與NSTimer相似的地方在於兩者都會在回撥時喚醒所在的RunLoop,但CADisplayLink會不斷處理來自核心的訊號,可能導致大量的不必要的資源損耗,因此使用CADisplayLink的時間應當保證儘可能的短暫,具體參考下面的文章連結

兩個定時器都能協助我們很好的實現動畫效果,更詳細的介紹參考iOS10定時訊息的改動。下面放上本篇部落格的動畫效果

12783864-2446f83df0fb2473

聲波動畫

聲波動畫參照自支付鴇的咻一咻功能,現在的版本貌似取消了(ps:吐槽一句支付鴇更新之後看個餘額都費勁)。從gif圖中不難看到動畫是由多個圖層縮放消失疊加在一起實現的,其中單個縮放消失的動畫在我上一篇按鈕動畫中有提到,基於上篇文章的動畫,筆者在點選按鈕的時候新增了一個NSTimer用來保證每隔一段時間新增一個動畫圖層。理論上來說可以將這些動畫的CAShapLayer儲存起來重複使用,但demo中偷懶,每次回撥建立新的圖層進行動畫

通過修改animation.duration來確定同一時間停留在螢幕上的圖層數量。另外,由於demo中每次回撥建立一個圖層,為了避免長時間動畫後,檢視上保留的CAShapeLayer過多時,在每次動畫結束後移除對應的圖層。

方法可以將圖層通過鍵值對的方式儲存在動畫物件animation中,並在動畫結束時取出圖層。iOS10之前所有NSObject的子類都自動遵守了動畫協議,但在iOS10中我們需要手動遵守CAAnimationDelegate

另外,圖層的位置是通過bounds + position來確認的,前者確認圖層大小尺寸,後者確認中心點

彈性動畫

認識CoreAnimation一文中展示過類似的彈性動畫,這裡對CoreAnimation動畫的流程進行介紹

  • 判斷keyPath對應屬性是否為可動畫屬性,如果否,不執行下一步
  • 根據toValuefromValue計算出動畫差值,根據duration屬性計算出動畫幀數,然後兩者計算出每一幀的圖層屬性
  • 根據fillMode引數判斷是否將圖層的presentation設定為動畫第一幀的圖層屬性並提交渲染
  • 逐幀設定presentation並渲染
  • 根據autoreverses判斷是否逆向執行一次動畫
  • 動畫結束呼叫代理物件的animationDidStop方法,根據isRemovedOnCompletion屬性判斷是否移除動畫
  • 如果上一步未移除動畫,根據fillMode屬性判斷是否將圖層設定為最後一幀的屬性。或者將presentation同步為模型樹屬性

上面是筆者使用CoreAnimation對流程的大致總結,具體可能還有改動,但基本如此。根據這些步驟,筆者使用CADisplayLink在螢幕重新整理時重新繪製圖層實現波浪效果,在製作這個動畫之前,我們先將波浪動畫的gif單獨放出來:

13783864-478a6514e44a4cbc

中間的彈出速度要快於兩邊,並且在達到最高點之後來回彈動。用彈簧動畫是可以很簡單的實現這種彈動效果,但是卻沒辦法幫我們繪製這種效果,即便有人告訴你彈簧的計算公式,然後讓你實現效果

 14783864-6a5ca37fd016c756
對於筆者這樣的學渣來說無疑是坑爹。所以為了能準確計算出中間的彈動效果,我們需要一些assistant來幫忙

為了不影響動畫視覺,這兩個view應該設定為hidden或者透明色。每次螢幕重新整理時,獲取兩個檢視的presentation的位置,然後繪製出路徑,設定到圖層上顯示

在使用者點選按鈕的時候,建立定時器物件,並且給兩個assistant新增對應的彈出動畫。這裡筆者兩個彈出都使用了CASpringAnimation彈簧動畫,經過多次試驗,如果referView只是使用簡單的移動動畫,整體的彈出效果會有些不自然。只要保證左右兩側的彈動力遠低於中間,就能看到很好的效果了

其他

使用assistant是一種動畫常見的方式,尤其在彈性動畫方面更是家常便飯。在開發中CoreAnimation已經能夠很好的應付95%的動畫效果,合理的結合定時器可以讓動效變得更加棒。最後吐槽一下蘋果的spring動畫,如果你嘗試在模擬器上slow animation,很容易就看到蘋果的彈性動畫回彈時是對稱的(⊙﹏⊙)b ,本文demo

上一篇:按鈕動畫

相關文章