CoreAnimation解析及中高階動畫實現

AlexCorleone同學發表於2017-09-27

一.CoreAnimation介紹

CoreAnimation是一套影像渲染和動畫基礎框架,其在iOS和OSX平臺用於顯示物件和實現動畫效果。使用CoreAnimation框架,動畫的大部分幀渲染都是蘋果為我們做好的。我們只需要配置幾個動畫引數(如開始和結束的點)並呼叫動畫開始的方法。接下來就把剩餘的工作交給CoreAnimation,操作全部實際繪圖工作是在圖形渲染硬體加速處理的。這個自動的影像加速器將會產生高幀頻和順滑的動畫效果而不會加重CPU的負荷、或使APP卡頓。

CoreAnimation是在UIKit和APPKit框架之下,並且被很好的整合到Cocoa和Cocoa Touch的view中。同時CoreAnimation也給出了一些擴充套件的動畫介面供我們使用。

下圖是CoreAnimation在cocoa框架中的層級(圖片來自蘋果)

CoreAnimation解析及中高階動畫實現
CoreAnimation

蘋果對於CoreAnimation的介紹中首先講述的是CALayer,因為CALayer是檢視顯示的基礎、同時是CAAnimation動畫產生的的載體。所有的動畫都是作用在CALayer上,通過更改CALayer的屬性,將每一幀渲染出來就形成了我們視覺的動畫效果。但是這篇部落格主要介紹CAAnimation,所以直接先忽略了前面的CALayer介紹,關於CALayer會在下一篇的文章中做詳細介紹。

二.CoreAnimation動畫

上面已經說過了,CoreAnimation是一套圖形渲染與動畫框架,CALayer負責圖形的渲染顯示,而CAAnimation及其子類則負責動畫的實現。通過CAAnimatin及其子類我們能夠相對簡單的實現一些複雜的layer動畫。

下面是整個CoreAnimation框架的所有動畫類結構:

CoreAnimation解析及中高階動畫實現
動畫類結構

1.動畫

CAAnimationCoreAnimation的抽象超類、而CAPropertyAnimation又是CAAnimation的抽象子類,正如我們所知道的我們不應該直接使用抽象類,而應該使用它們的子類,如CABasicAnimation(基礎動畫)、CAKeyFrameAnimation(關鍵幀動畫)、CASpringAnimation(彈簧動畫)等。

1.1 CAAnimation

CAAnimationCoreAnimation的抽象超類,也是整個動畫的核心類,大部分的動畫屬性與方法都是在該類中實現的。CAAnimation之所以能夠擁有這些動畫相關的屬性和方法是因為該類遵守了CAMediaTiming CAAction兩個協議。CAMediaTiming協議主要實現一些控制動畫執行時間的屬性和函式(包含動畫的開始時間 -> beginTime、執行時間 -> duration、執行速率 -> speed、執行時間偏移量 -> timeOffset、重複執行的次數 -> repeatCount、動畫執行結束的處理 ->filleMode等),因此CAAnimation能夠很好的處理時間與layer動畫的關係;CAAction主要實現一些動作觸發的響應介面,遵守該協議的物件可以指定CALayer響應的行為,如新增一個動畫效果,或者執行其他的tasks。

timingFunction:屬性用於設定動畫執行的時間步調,建立該物件相對簡單,可以直接使用kCAMediaTimingFunction系列巨集指定動畫執行的時間為`linear', `easeIn', `easeOut' and `easeInEaseOut'或者也可以使用貝塞爾曲線函式建立一個CAMediaTimingFunction物件貝塞爾曲線控制點獲取

delegate:設定Animation的代理物件,這樣我們可以獲取動畫執行過程的一些狀態,包括動畫的開始和結束,如果你只是想在結束時獲得回撥通知,也可以呼叫setCompletionBlock:函式,設定動畫完成的block回撥。

removedOnCompletion:動畫執行結束是否移除動畫,預設YES,但是該引數必須與fillMode = kCAFillModeForwards 或者 kCAFillModeBoth同時設定才能實現在動畫結束不移除動畫layer。

1.2 CAPropertyAnimation

CAPropertyAnimationCAAnimation的抽象子類,使用該類可以建立一個操作CALayer屬性值的Animation物件。該類主要實現介面用於指定實現動畫的CALayer的屬性。

1.3 CABasicAnimation

CABasicAnimationCAPropertyAnimation的子類,該類實現了三個屬性fromValue、byValue、toValue、用於描述一個單關鍵幀動畫執行過程的三個屬性值。

1.4 CAKeyFrameAnimation

CAKeyFrameAnimationCAPropertyAnimation的子類,該類用於實現多關鍵幀動畫。我們可以將動畫主要的一些幀值新增到陣列,賦值給values屬性,再把每一幀對應的時間新增到keyTimes屬性,(值得注意的是keyTimes的值必須在【0,1】之間,陣列中的值按照陣列的index依次增大,並且所有值加在一起的和等於一),如果想要為每一幀指定一個CAMediaTimingFunction物件,也可以建立對應的CAMediaTimingFunction物件並加到陣列,然後賦值給timingFunctions屬性。

CAKeyFrameAnimation最強大的地方在於他有一個path屬性,當我們建立一個路徑並賦值給path屬性時,動畫就會按照我們指定的路徑軌跡執行。

1.5 CASpringAnimation

CASpringAnimation繼承於CABasicAnimation類,正如它的名字Spring一樣,該類主要用於實現一些類似彈簧的動畫效果。mass屬性相當於物體的重量,stiffness屬性代表了彈簧的剛度,damping屬性代表阻尼係數,initialVelocity屬性代表動畫的初始速度,settlingDuration是動畫的預估執行時間。通過這些屬性值,我們可以控制Spring動畫的拉伸幅度,動畫的執行時間等。

2.組動畫

在動畫使用的過程中,我們一般不會只使用一個動畫,我們可能為複雜的動畫效果建立多個Animation物件,然後將這些物件分別新增到Layer動畫中,這種方式能夠實現但是相對比較麻煩,我們可以使用組動畫解決這個問題。 對於組合動畫我們可以使用CATransition()和CAAnimationGroup, CAAnimationGroup將多個動畫合併為一組,並且我們可以指定動畫關聯時間讓組內的動畫可以同時或者按步驟執行,CATransaction將多個layer-tree更改操作放在一起執行並自動更新到render tree。

2.1 CAAnimationGroup

CAAnimationGroupCAAnimation的子類,該動畫將多個動畫放到一個animations陣列,新增到layer,這些動畫是並行執行的,當然你也可以設定例如beginTime這樣的屬性使動畫按照一定的順序執行。

2.2CATransition()

CATransition繼承於CAAnimation,該動畫主要實現一些過渡效果。你可以為type屬性設定`fade', `moveIn', `push' and `reveal'來實現你想要的動畫效果,同時你也可以設定subtype為`fromLeft', `fromRight', `fromTop' and`fromBottom'來指定動畫的方向。startProgressendProgress用於控制開始和結束的進度,範圍必須在【0,1】。

3.動畫執行時間

時間是動畫的重要部分之一,我們可以通過CAMediaTiming協議的方法和屬性指定動畫的時間資訊。在CoreAnimation中遵守這個協議的有兩個類。CAAnimation類採用了這個協議,因此可以為Animations執行指定時間資訊。CALayer類也採用了該協議,因此也可以為隱式動畫指定Animations執行相關的時間資訊,值得注意的是隱式動畫優先採用預設的時間資訊。

想想時間和動畫的關係,理解layer物件是如何和時間相互作用的是非常重要的。每一個layer物件都有一個本地的時間去管理動畫時間。通常在動畫過程中的兩個layer的本地時間非常接近,接近到我們可能察覺不到有什麼不同。本地時間可以被父layer或者自己擁有的timing引數更改

CALayer類定義了convertTime:fromLayer: convertTime:toLayer:方法,為了確保時間值適用於layer。我們可以使用這些方法將layer的時間值轉換為相對於本地時間或者另一個layer時間值的精確時間。使用這些方法需要考慮到對layer的本地時間的影響,同時這些方法會返回一個可以在其他的layer中使用的值。

一旦我們有了一個layer的本地時間值,我們就可以使用這個值去更新Animation物件或者layer的相關屬性,使用CAMediaTiming協議屬性,我們可以實現一些有趣的動畫效果,包括:

1.我們可以使用beginTime屬性設定Animation的開始時間。通常情況,Animations的開始時間是在下一次更新迴圈(the next update cycle),但是我們可以設定beginTime引數來延遲動畫的執行時間。我們可以設定後一個動畫的beginTime為前一個動畫的結束時間,這樣多個動畫按照一定的順序執行。

2.使用timeOffset屬性可以在一組動畫中設定相對於其他動畫,延遲執行一定的時間段。

4.動畫的新增與刪除

我們建立好動畫物件可以呼叫CALayeraddAnimation:forKey:方法將動畫新增到layer上並指定動畫的標記key用於後續的刪除操作,如果要移除一個動畫可以呼叫CALayerremoveAnimationForKey:方法移除key值對應的動畫效果、或者你可以呼叫removeAllAnimations方法刪除layer附帶的所有動畫效果,並且remove方法是立即生效的,動畫立即結束執行。

三.CoreAnimation動畫實現方式

通過更改Layer的屬性值實現動畫。(屬性必須是Animatable關於CALayer的可做動畫的屬性)

在這裡更改屬性值建立動畫有兩種:

第一種是隱式動畫(Animating a change implicitly),隱式動畫使用預設的時間(0.25秒)和動畫屬性去執行動畫。當我們更改layer的屬性值時,會觸發隱式動畫。當修飾的layer物件在layer-tree中時,更新會立即執行。如果layer物件的顯示效果沒有立即改變,CoreAnimation會為這些改變建立一個觸發器並且新增一個或者多個隱式動畫去執行。因此,像theLayer.opacity = 0.0;這樣的更改會引發CoreAnimation為你建立一個Animation物件,並把這個Animation物件加入到下一次更新迴圈(next update cycle.)中去執行。

第二種是顯式動畫(Animating a change explicitly),需要你自己為使用的動畫物件配置屬性。如上的隱式動畫如果要顯示的執行,則需要我們建立一個Animation物件(如:CABasicAnimation)。併為這個物件配置動畫引數。我們可以在把這個Animation新增到layer之前設定Animation的開始和結束值、動畫的執行時間、或者設定其他的動畫屬性。當建立一個Animation物件,你需要指定動畫的KeyPath並設定動畫引數。去執行動畫時,只需要呼叫addAnimation:forKey方法去將你想要執行的動畫新增到layer上。顯示動畫的layer屬性更新不像隱式動畫,顯示動畫只是建立動畫不會更改layer-tree中的屬性值。在動畫的結束CoreAnimation會移除動畫並使用它當前的屬性值重繪layer。如果你想要通過顯示動畫永久更改layer-tree中的屬性值,那麼你需要在動畫結束時手動設定layer的屬性。

隱式動畫和顯示動畫通常是在當前的執行環(run loop)結束之後執行的,並且當前執行緒一定要有一個執行環去執行Animations。如果更改多個屬性或者為layer新增Animations,那麼這些改變或者新增的動畫是併發執行的。當然也可以為每個動畫設定特定的執行時間,具體的使用下面會有程式碼。

1.使用UIView的分類實現動畫

儘管我們可以直接使用CAAnimation介面實現想要的動畫效果,但是對於簡單的動畫使用CAAnimation還是需要額外的步驟,其實蘋果已經為我們做了一些擴充套件,這些擴充套件在UIView的分類中實現,所以對於UIView自帶的layer我們可以直接使用UIView去實現一些簡單的動畫。關於如何實現UIView自帶的layer動畫可以看這裡How to Animate Layer-Backed Views.

下面是通過UIView動畫分類介面實現的動畫效果:

1.實現更改view透明度動畫

CoreAnimation解析及中高階動畫實現
透明度

2.實現更換view背景色動畫並延遲0.5秒執行

CoreAnimation解析及中高階動畫實現
背景色

3.實現view移動動畫

CoreAnimation解析及中高階動畫實現
移動

4.實現view旋轉動畫

CoreAnimation解析及中高階動畫實現
旋轉

5.實現view放大縮小動畫

CoreAnimation解析及中高階動畫實現
放大
CoreAnimation解析及中高階動畫實現
縮小

6.實現view彈簧效果動畫

CoreAnimation解析及中高階動畫實現
彈簧

7.實現view系統刪除動畫

CoreAnimation解析及中高階動畫實現
系統刪除

8.實現過渡動畫

CoreAnimation解析及中高階動畫實現
過渡

9.事務實現view翻轉動畫

CoreAnimation解析及中高階動畫實現
事務翻轉

10.實現view組合動畫

CoreAnimation解析及中高階動畫實現
UIView組合動畫


2.使用CAAnimation實現動畫

UIView自帶的動畫是蘋果給我提供的CAAnimation的封裝,其動畫實現相對來說比較簡單方便,我們只需要在block內更改UIView的屬性便可以實現一些簡單的動畫效果。但是其侷限性也是十分明顯的。對於一些複雜動畫、高階動畫UIView自帶的動畫就顯得無能為力,這時CAAnimation的強大之處就無語言表了。其實CAAniamtion動畫的使用也不是很困難,但是其對於控制動畫執行時間、數學知識運用以及超常的想象力等要求就比較高了。

下面是對照UIView自帶動畫介面實現的一些動畫,並簡單列舉了幾個動畫效果,對於UIView自帶動畫來說實現相對困難,以此來展示下CAAnimation的強大。

1.實現更改view透明度動畫

CoreAnimation解析及中高階動畫實現
透明度

2.實現更改view的背景色

CoreAnimation解析及中高階動畫實現
背景色

3.實現view移動動畫

CoreAnimation解析及中高階動畫實現
移動

3.實現view曲線移動

CoreAnimation解析及中高階動畫實現
曲線移動

4.實現view旋轉動畫

CoreAnimation解析及中高階動畫實現
旋轉

5.實現viewX軸翻轉動畫

CoreAnimation解析及中高階動畫實現
X軸翻轉

6.實現viewY軸翻轉動畫

CoreAnimation解析及中高階動畫實現
Y軸翻轉

7.實現view放大縮小動畫

CoreAnimation解析及中高階動畫實現
放大
CoreAnimation解析及中高階動畫實現
縮小
CoreAnimation解析及中高階動畫實現
函式實現

8.實現view過渡動畫

CoreAnimation解析及中高階動畫實現
過渡
CoreAnimation解析及中高階動畫實現
函式實現

9.實現view彈簧動畫

CoreAnimation解析及中高階動畫實現
彈簧動畫
CoreAnimation解析及中高階動畫實現
函式實現

10.事務動畫

CoreAnimation解析及中高階動畫實現
事務

11.實現view組動畫

CoreAnimation解析及中高階動畫實現
組動畫
CoreAnimation解析及中高階動畫實現
函式實現

四.自定義動畫

上面說了那麼多,但是建立的動畫效果都還是比較普通的。對於CAAnimation類族,這些只是他們強大功能的冰山一角。但是無論多麼複雜的動畫其實都是上面這些基礎動畫的聚合,只要我麼能夠想象出動畫的執行邏輯,我們就可以使用CAAnimation類族實現相對複雜的動畫。本人的想象力有限,於是我模仿微博的tabbar中間item點選按鈕的點選彈出選單效果,實現了簡單的彈出選單,具體的程式碼:clone git程式碼。由於不能上傳視訊所以這裡就不放效果圖了,感興趣的可以去下載工程執行試看。

五.總結

這篇部落格主要介紹了CoreAnimation的動畫使用,以及動畫的實現。雖然CAAnimation類族的使用並不困難,但是還是有很多細節需要注意的。

1.顯示動畫在執行過程中的屬性值修改並不會影響到layer-tree中的layer屬性值,所以在動畫執行結束,layer會回到原始狀態。

2. 對於CALayer如果多次呼叫addAnimation: forKey:只會執行最後新增的Animation物件。

3. 對於一些屬性值不是OC物件的需要將對應的結構體或者基本資料型別轉化為OC物件,比較特殊的是顏色值,要將UIColor轉化為CGColor並對其進行id強轉。具體的屬性值轉換下表有對應的轉換物件。

4. 其實動畫中比較強大的屬性是CALayertransform屬性,該屬性可以實現3D動畫效果,蘋果也給出了一些transform的便捷keyPath,如rotation.xscale.ytranslation.z等。

5. 還有一點需要注意的是CAAnimation物件屬性的設定必須在新增到CALayer之前,否則設定不起作用。

做為一個iOS菜鳥希望自己能夠不斷提高自己的擼碼能力的同時,也給大家帶來更多的貢獻;馬上就要十一了, 提前祝大家節日快樂、happy coding。

終於結束了,謝謝大家的閱讀!覺得不錯的朋友記得點個喜歡哦!有什麼不足的希望大家評論指出,或者QQ我(1034131730)。


注:以下是一些小的細節

屬性值得轉換:

當我們建立動畫更改的layer屬性為C語言的結構體時,我們必須將這些結構體轉換為一個物件賦值給layer下面的表列出了C語言型別對應的轉換Obj-C物件。

CoreAnimation解析及中高階動畫實現
動畫屬性值轉換

CATransform3D的一些便捷的KeyPaths:

CoreAnimation解析及中高階動畫實現
CATransform3D




相關文章