你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> iOS 動畫效果:Core Animation & Facebook

iOS 動畫效果:Core Animation & Facebook

編輯:IOS開發基礎

303.jpg

本文為投稿文章,作者:小袋子


前言
相信很多人對實現 iOS 中的動畫效果都特別頭疼,往往懶得動手,功能實現不就得了,何必要那麼花哨、裝13的東西。但是看到別人的炫酷動效,心中又瘙癢不已,便下定決心學習,於是開始翻看 Core Animation、UIView動畫(其實是對Core Animation的一種封裝)相關資料。不小心看到一群大神正在熱烈討論,鑽一進去一看,原來是 POP (潛意識:Facebook出品必屬精品),這還學什麼Core Animation,果斷pod一個來玩玩,於是你就左手CA,右手 POP 開森地把玩起來了。

此時,你可能已經學會了CA的基本使用方法,也對UIView動畫的便捷感到驚喜,但是不滿足的你,顯然有更高的追求,POP 以其靈活的用法,豐富的動效,完整的API文檔,深得很多程序員的喜愛。作為一個有逼格的程序員,這麼流行的框架,必然是值得深入學習的,但是你是否考慮過這樣的第三方動畫框架是否存在什麼不足。因此,作為一個有追求的程序員,有必要來稍微深入地探討一下 Core Animation 和 POP 不同點。

Core Animation 工作機制

首先我們需要了解CA是如何工作的。每當我們創建並添加動畫到 layer 時,QuartzCore 框架就會把動畫的參數打包好,然後通過 IPC (處理器)發送給名為 backboardd 的後台處理程序。你的應用也會發送當前展示在屏幕上的每一個 layer 的信息。

backboardd 會處理 layer 的結構體系然後通過 OpenGL 繪制出來。它還會處理你已經添加過的動畫(也可以是視圖,因為視圖本質是包裹著 layer的)。你一定要理解的是,backboardd 使得動畫的每一幀都可以在你的應用中完全獨立。這裡唯一的回調是動畫的開始和結束(詳見CAAnimationDelegate 協議)。你的應用完全不會參與動畫的繪制,這些繪制完全獨立於你的應用進程(除非你明確地在你的應用中通過動畫通用屬性要求繪制動畫幀)。這意味著你可以繼續在主線程做其他事情,並且不會影響到 CAAnimation 的性能。如果你阻塞了你的主線程,或者你在調試器中暫停了你的程序,你的動畫還是會繼續執行。

但是你可能會有這樣的疑問:每個 CALayer 不是還有一個 presentationLayer 屬性嗎?

presentationLayer的官方解釋:

“While an animation is in progress, you can retrieve this object and use it to get the current values for those animations.”

當CAAnimation發生時,你在屏幕上看到的實際上是 presentation layer 的改變。如果你訪問 presentation layer,QuartzCore 將會計算現有的幀狀態,並且使用這個幀狀態去構建 presentation layer 對象。因為動畫狀態在動畫執行期間一直處於改變,因此你將會獲得近似值。

POP 工作機制

現在有很多優秀的第三方動畫庫,POP 因為其使用靈活、功能強大、文檔齊全,所以備受好評,先看一下官方介紹:

POP是一個在iOS與OS X上通用的極具擴展性的動畫引擎 它在基本的靜態動畫的基礎上增加的彈簧動畫與衰減動畫。

使之能創造出更真實更具物理性的交互動畫 POP的API可以快速的與現有的ObjC代碼集成並可以作用於任意對象的任意屬性。

POP是個相當成熟且久經考驗的框架 Facebook出品的令人驚歎的Paper應用中的所有動畫和效果即出自POP。

更為詳細的介紹和使用請查看官方文檔以及裡脊串的 POP介紹與使用實踐(快速上手動畫)。

POP 本質上是基於定時器的動畫庫,使用每秒 60 頻率的定時器,即時鐘頻率為 1/60 秒(為了匹配 iOS 顯示屏幀率),使得動畫刷新繪制頻率與屏幕刷新頻率一致。很多這類動畫庫都使用 CADisplayLink 做為一個回調源。

一旦定時器刷新,動畫庫計算動畫的進程,這意味著動畫庫會計算那些活動的東西的狀態(通常是layer 屬性,如 bound,opactiy,transform 等)。然後動畫庫提供最新計算的值給有動畫的 layer (或者其他對象)。最主要的區別是,layer 的狀態將會在這種情況下改變。

由於 layer 的一些參數已經被改變,你的應用必須通過 IPC 通知 backboardd 處理這些變化。當 backboardd 接收到變化通知(同時接收到的還有應用中的 layer 樹),它將在屏幕上重繪一切東西。這意味著,你應用中做的每一個動畫幀都會傳送數據到 backboardd (即通知 backboardd ),因為 backboardd 完全不知道 layer 發生了什麼事情。綜上,你的應用就是在這種情況下運行動畫的。

Core Animation 和 POP 運行動畫對比

由於 POP 是基於定時器定時刷新添加動畫的原理,那麼如果將動畫庫運行在主線程上,會由於線程阻塞的問題導致動畫效果出現卡頓、不流暢的情況。更為關鍵的是,你不能將動畫效果放在子線程,因為你不能將對 view 和 layer 的操作放到主線程之外。

為了驗證上述的觀點,我做了一個實驗,首先用CA動畫制作一個可以旋轉的 view:

UIView?*viewCA?=?[[UIView?alloc]initWithFrame:CGRectMake(50,50,?100,?100)];
???viewCA.backgroundColor?=?[UIColor?blueColor];
???[self.view?addSubview:viewCA];
???CABasicAnimation?*caAnimation?=?[CABasicAnimation?animationWithKeyPath:@"transform.rotation.z"];
???caAnimation.toValue?=?@(M_PI);
???caAnimation.duration?=?2.0;
???caAnimation.repeatCount?=?500;
???[viewCA.layer?addAnimation:caAnimation?forKey:@"anim"];

再創建一個利用 POP 動畫庫制作的可旋轉 view:

UIView?*viewPOP?=?[[UIView?alloc]initWithFrame:
CGRectMake(CGRectGetWidth(self.view.bounds)?-?100?-?50,?50,?100,?100)];
???viewPOP.backgroundColor?=?[UIColor?yellowColor];
???[self.view?addSubview:viewPOP];
???POPBasicAnimation?*popAnimation?=?[POPBasicAnimation?animationWithPropertyNamed:kPOPLayerRotation];
???popAnimation.toValue?=?@(M_PI);
???popAnimation.duration?=?2.0;
???popAnimation.repeatCount?=?500;
???[viewPOP.layer?pop_addAnimation:popAnimation?forKey:@"rotation"];

在沒有線程阻塞的情況下,對比兩個動畫庫的運行效果如下:

37.gif

可以看出來雖然在沒有線程阻塞,但是 POP 的動畫在結束時有一個明顯的停止動作,是因為 POP 的動畫效果不好嗎?

答案是 timingFunction

CoreAnimation 和 POPBasicAnimation提供同樣的五種 timingFunction:

  • kCAMediaTimingFunctionLinear

  • kCAMediaTimingFunctionEaseIn

  • kCAMediaTimingFunctionEaseOut

  • kCAMediaTimingFunctionEaseInEaseOut

  • kCAMediaTimingFunctionDefault

重點說一下:kCAMediaTimingFunctionDefault(引自:iOS-Core-Animation-Advanced-Techniques(五))

它和kCAMediaTimingFunctionEaseInEaseOut很類似,但是加速和減速的過程都稍微有些慢。它和kCAMediaTimingFunctionEaseInEaseOut的區別很難察覺,可能是蘋果覺得它對於隱式動畫來說更適合(然後對UIKit就改變了想法,而是使用kCAMediaTimingFunctionEaseInEaseOut作為默認效果),雖然它的名字說是默認的,但還是要記住當創建顯式的CAAnimation它並不是默認選項(換句話說,默認的圖層行為動畫用kCAMediaTimingFunctionDefault作為它們的計時方法)。

如果不設置 timingFunction 屬性,那麼在使用 CA 的情況下, timingFunction 是kCAMediaTimingFunctionLinear 的,而 POP 卻是kCAMediaTimingFunctionEaseOut ,因此我們只要添加這麼一行代碼:

popAnimation.timingFunction?=?[CAMediaTimingFunction?functionWithName:kCAMediaTimingFunctionLinear];

現在再看效果:

38.gif


可以看出來,在主線程沒有阻塞的情況下,兩種動畫庫的表現並無差異。

現在我們來制造一點難度,人工利用線程的 sleep 增加一個主線程阻塞:

-?(void)repeatedlyBlockMainThread
{
????NSLog(@"blocking?main?thread!");
????[NSThread?sleepForTimeInterval:0.25];
????[self?performSelector:@selector(repeatedlyBlockMainThread)?withObject:nil?afterDelay:1];
}

然後再 viewDidLoad 裡面調用 :

[self?performSelector:@selector(repeatedlyBlockMainThread)?withObject:nil?afterDelay:1];

現在再來看一下兩者的動畫效果:

39.gif

很明顯,我們可以看出來,由於添加了主線程阻塞,利用 POP 制作的動畫視圖,在每隔 1s 都會卡頓一下,而 CA 的視圖卻完全不受主線程阻塞的影響。

總結

通過這次簡單的對比,我們從工作機制上了解了 CA 和 POP 兩個動畫庫的基本原理,並用簡單的動畫效果對比,重現了在主線程阻塞的情況下兩者的差異,很顯然, POP 受主線程阻塞的影響很大,在使用過程中,應避免在有可能發生主線程阻塞的情況下使用 POP ,避免制作卡頓的動畫效果,產生不好的用戶體驗。文中提出了 POP 的這種缺點,但是 POP 畢竟是久經考驗的動畫技術,本人也正在學習中,有錯誤的地方吝請指正。

對比系列,是個人比較喜歡的一種學習方式,通過對比,找出不同技術的優缺點,可以更合理地使用這些武器,俗話說:好鋼用在刀刃上,大抵如此。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved