前言
本次分享將從以下方面進行展開:
- 曾被面試官問倒過的問題:層與視圖的關系
CALayer
類介紹及層與視圖的關系CAShapeLayer
類介紹UIBezierPath
貝塞爾曲線講解CoreAnimation
之動畫子類介紹CATransitionAnimation
類實現各種過濾動畫
關於Core Animation
在iOS
系統中的關系圖如下:
可以看出,Core Animation
是相對上層的封裝,介於UIKit
與Core Graphics
、OpenGL/OpenGL ES
之間。最底下還有一個Graphics Hardware
,就是硬件了!!!
層與視圖的關系
我們先看看Window
與Layer
之間的關系:
這個圖告訴我們,層是基於繪畫模型實現的,層並不會在我們的app
中做什么事,實際上是層只是捕獲app
所提供的內容,並緩存成bitmap
,當任何與層關聯的屬性值發生變化時,Core Animation
就會將新的bitmap
傳給繪圖硬件,並根據新的位圖更新顯示。
UIView
是iOS
系統中界面元素的基礎,所有的界面元素都是繼承自UIView
。它本身完全是由CoreAnimation
來實現的。它真正的繪圖部分,是由一個CALayer
類來管理。UIView
本身更像是一個CALayer
的管理器,訪問它的跟繪圖和跟坐標有關的屬性,例如frame
、bounds
等,實際上內部都是在訪問它所包含的CALayer
的相關屬性。
提示:
layer-based drawing
不同於view-based drawing
,后者的性能消耗是很高的,它是在主線程上直接通過CPU
完成的,而且通常是在-drawRect:
中繪制動畫。
UIView與CALayer的聯系
我們看看UIView
與layer
之間的關系圖:
我們可以看到,一個UIView
默認就包含一個layer
屬性,而layer
是可以包含sublayer
的,因此形成了圖層樹。從此圖可以看出這兩者的關系:視圖包含一個layer
屬性且這個layer
屬性可以包含很多個sublayer
。
有人說UIView
就像一個畫板,而layer
就像畫布,一個畫板上可以有很多塊畫布,但是畫布不能有畫板。
UIView與CALayer的主要區別
UIView
是可以響應事件的,但是CALayer
不能響應事件UIView
主要負責管理內容,而CALayer
主要負責渲染和呈現。如果沒有CALayer
,我們是看不到內容的。CALayer
維護着三個layer tree
,分別是presentLayer Tree
、modeLayer Tree
、Render Tree
,在做動畫的時候,我們修改動畫的屬性,其實是修改presentLayer
的屬性值,而最終展示在界面上的其實是提供UIView
的modelLayer
。
官方說明了UIView
與CALayer
的聯系:
Layers are not a replacement for your app’s views—that is, you cannot create a visual interface based solely on layer objects. Layers provide infrastructure for your views. Specifically, layers make it easier and more efficient to draw and animate the contents of views and maintain high frame rates while doing so. However, there are many things that layers do not do. Layers do not handle events, draw content, participate in the responder chain, or do many other things. For this reason, every app must still have one or more views to handle those kinds of interactions.
說說CALayer
我們首先得明確Layer
在iOS
系統上的坐標系起點是在左上角的,而在OS X
系統上是左下角的:
筆者對Layer
相關的屬性和方法畫了這么一張圖:
看看官方關於Layer Tree
的說明:
。
Core Animation介紹
我們在開發中常見的動畫:
筆者將Core Animation
的關系圖及相關屬性、方法說明都通過該圖來表達:
如果我們要改變動畫的行為,我們可以實現CAAction
協議的方法,像這樣:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
- (id<CAAction>)actionForLayer:(CALayer *)theLayer
forKey:(NSString *)theKey {
CATransition *theAnimation=nil;
if ([theKey isEqualToString:@"contents"]) {
theAnimation = [[CATransition alloc] init];
theAnimation.duration = 1.0;
theAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
theAnimation.type = kCATransitionPush;
theAnimation.subtype = kCATransitionFromRight;
}
return theAnimation;
}
|