CoreAnimation解析及中高級動畫實現

一.CoreAnimation介紹

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

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

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

CoreAnimation

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

二.CoreAnimation動畫

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

下面是整個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透明度動畫

透明度

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

背景色

3.實現view移動動畫

移動

4.實現view旋轉動畫

旋轉

5.實現view放大縮小動畫

放大
縮小

6.實現view彈簧效果動畫

彈簧

7.實現view系統刪除動畫

系統刪除

8.實現過渡動畫

過渡

9.事務實現view翻轉動畫

事務翻轉

10.實現view組合動畫

UIView組合動畫


2.使用CAAnimation實現動畫

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

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

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

透明度

2.實現更改view的背景色

背景色

3.實現view移動動畫

移動

3.實現view曲線移動

曲線移動

4.實現view旋轉動畫

旋轉

5.實現viewX軸翻轉動畫

X軸翻轉

6.實現viewY軸翻轉動畫

Y軸翻轉

7.實現view放大縮小動畫

放大
縮小
函數實現

8.實現view過渡動畫

過渡
函數實現

9.實現view彈簧動畫

彈簧動畫
函數實現

10.事務動畫

事務

11.實現view組動畫

組動畫
函數實現

四.自定義動畫

上面說了那么多,但是創建的動畫效果都還是比較普通的。對于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.x、scale.ytranslation.z等。

5.?還有一點需要注意的是CAAnimation對象屬性的設置必須在添加到CALayer之前,否則設置不起作用。

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

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



注:以下是一些小的細節

屬性值得轉換:

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

動畫屬性值轉換

CATransform3D的一些便捷的KeyPaths:

CATransform3D



最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 在iOS中隨處都可以看到絢麗的動畫效果,實現這些動畫的過程并不復雜,今天將帶大家一窺iOS動畫全貌。在這里你可以看...
    F麥子閱讀 5,143評論 5 13
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現這些動畫的過程并不復雜,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,572評論 6 30
  • 書寫的很好,翻譯的也棒!感謝譯者,感謝感謝! iOS-Core-Animation-Advanced-Techni...
    錢噓噓閱讀 2,326評論 0 6
  • 在iOS實際開發中常用的動畫無非是以下四種:UIView動畫,核心動畫,幀動畫,自定義轉場動畫。 1.UIView...
    請叫我周小帥閱讀 3,169評論 1 23
  • 系列文章: 老司機帶你走進Core Animation 之CAAnimation 老司機帶你走進Core Anim...
    老司機Wicky閱讀 17,876評論 53 194