一、作用對象對比
CoreAnimation 只能作用于 CALayer;而Pop Animation可以是任意基于NSObject的對象;
CALayer補充:結構跟UIView的subView一樣,都是一個樹形的結構
重繪機制:當調用setNeedsDisplay的時候會重新調用render方法,而CALayer實際是維護個三個模型的樹形結構,一個是渲染樹,一個是呈現樹,還有一個是當前模型樹:
模型樹(Model Tree)直接創建的或者通過UIView獲得的(view.layer)用于顯示的圖層樹,稱之為模型樹(Model Tree);
模型樹的背后還存在兩份圖層樹的拷貝,一個是呈現樹(Presentation Tree),一個是渲染樹(Render Tree).呈現樹(Presentation Tree),呈現樹可以通過普通layer(其實就是模型樹)的layer.presentationLayer獲得,模型樹則可以通過layer.modelLayer屬性獲得。當給一個CALayer添加動畫時,動畫其實沒有改變這個layer的實際屬性,取而代之,系統會創建一個Model layer的復制品:Presentation Layer;Presentation Layer的屬性值和動畫運行過程中界面上看到的是一致的.Pop Animation應用于CALayer時,在動畫運行的任何時刻,layer和其presentationLayer的相關屬性值始終保持一致,而Core Animation做不到。
渲染樹(Render Tree),渲染樹是私有的,你無法訪問到,渲染樹是對呈現樹的數據進行渲染,為了不阻塞主線程,渲染的過程是在單獨的進程或線程中進行的,所以Animation的動畫并不會阻塞主線程.
我們在寫動畫時,通常會設置 removedOnCompletion = NO;設置 fillMode 為kCAFillModeForwards。這是因為系統會在duration 后自動銷毀這個 layer 的 Presentation Layer ,只留下 Model Layer,不設置的話動畫結束后會回到初始狀態。
二、工作機制對比
Core Animation 工作機制
每當我們創建并添加動畫到 layer 時,QuartzCore 框架就會把動畫的參數打包好,然后通過處理器發送給名為 backboardd 的進程處理程序。你的應用也會發送當前展示在屏幕上的每一個 layer 的信息。
backboardd 會處理 layer 的結構體系然后通過 OpenGL 繪制出來。backboardd 使得動畫的每一幀都可以在你的應用中完全獨立。你的應用完全不會參與動畫的繪制,這些繪制完全獨立于你的應用進程。這意味著你可以繼續在主線程做其他事情,并且不會影響到 CAAnimation 的性能。如果阻塞了主線程,或者你在調試器中暫停了你的程序,動畫還是會繼續執行。
POP 工作機制
POP 本質上是基于定時器的動畫庫,使用每秒 60 頻率的定時器 CADisplayLink,使得動畫刷新繪制頻率與屏幕刷新頻率一致。
一旦定時器刷新,動畫庫計算動畫的進程,這意味著動畫庫會計算 layer 的屬性,如 bound,opactiy,transform 等。然后動畫庫提供最新計算的值給有動畫的 layer (或者其他對象)。最主要的區別是,layer 的狀態將會在這種情況下改變。
由于 layer 的一些參數已經被改變,應用必須通過處理器通知 backboardd 進程處理這些變化。當 backboardd 接收到變化通知,它將在屏幕上重繪。這意味著,應用中做的每一個動畫幀都會傳送數據到 backboardd
由于 POP 是基于定時器定時刷新添加動畫的原理,那么如果將動畫庫運行在主線程上,會由于線程阻塞的問題導致動畫效果出現卡頓、不流暢的情況。更為關鍵的是,你不能將動畫效果放在子線程,因為你不能將對 view 和 layer 的操作放到主線程之外。
- (void)viewDidLoad {
[super viewDidLoad];
CABasicAnimation *rotationAnim = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
rotationAnim.toValue = @(M_PI);
rotationAnim.duration = 2;
rotationAnim.repeatCount = 20;
[self.blueView.layer addAnimation:rotationAnim forKey:nil];
POPBasicAnimation *popAnim = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerRotation];
popAnim.toValue = @(M_PI);
popAnim.duration = 2;
popAnim.repeatCount = 20;
popAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[self.yellowView.layer pop_addAnimation:popAnim forKey:nil];
[self performSelector:@selector(causeMainThread) withObject:nil afterDelay:1];
}
-(void)causeMainThread
{
// 即便線程發生死鎖,CoreAnimation也會繼續執行
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"111");
});
// [NSThread sleepForTimeInterval:0.25];
// [self performSelector:@selector(causeMainThread) withObject:nil afterDelay:1];
}
POP 受主線程阻塞的影響很大,因此,在使用過程中,應避免在有可能發生主線程阻塞的情況下使用 POP ,避免制作卡頓的動畫效果,產生不好的用戶體驗。
三、使用效果對比
Pop 提供了很多類似于 CoreAnimation 的效果。在技術選擇上,如果只是簡單的 UIView 屬性的動畫則選擇 [UIView animationWith...];如果需要CALayer做一些比較復雜的效果,但又不想引入第三方動畫庫,在執行效率上要求高,則首選CoreAnimation;但如果要求展現一些“果凍效果”,Pop 的 POPSpringAnimation 會比CoreAnimation 在參數調整上更簡便易用。
CoreAnimation 自帶的彈簧效果,從 iOS 7 開始被廣泛應用在系統動畫中。自 iOS 8 開始,Apple 公開了 Spring Animation 的 API,開發者也可以使用簡單的代碼創建這類動畫效果:
+ (void)animateWithDuration:(NSTimeInterval)duration
delay:(NSTimeInterval)delay
usingSpringWithDamping:(CGFloat)dampingRatio
initialSpringVelocity:(CGFloat)velocity
options:(UIViewAnimationOptions)options
animations:(void (^)(void))animations
completion:(void (^)(BOOL finished))completion
而 CASpringAnimation 是iOS9才引入的動畫類,它繼承于CABaseAnimation
CASpringAnimation 參數說明:
- mass: 質量,影響圖層運動時的彈簧慣性,質量越大,彈簧拉伸和壓縮的幅度越大
- stiffness: 剛度系數(勁度系數/彈性系數),剛度系數越大,形變產生的力就越大,運動越快
- damping: 阻尼系數,阻止彈簧伸縮的系數,阻尼系數越大,停止越快
- initialVelocity:初始速率,動畫視圖的初始速度大小
速率為正數時,速度方向與運動方向一致,速率為負數時,速度方向與運動方向相反 - settlingDuration: 結算時間,返回彈簧動畫到停止時的估算時間,根據當前的動畫參數估算,通常彈簧動畫的時間使用結算時間比較準確
POPSpringAnimation 參數說明:
- springBounciness 反彈-影響動畫作用的參數的變化幅度
- springSpeed 速度
- dynamicsTension 拉力-影響回彈力度以及速度
- dynamicsFriction 摩擦力-如果開啟,動畫會不斷重復,幅度逐漸削弱,直到停止。
- Mass 質量-細微的影響動畫的回彈力度以及速度