今天單純說(shuō)一下CALayer里面有的屬性和方法。反正宗旨就是隨意。
打開(kāi)CALayer定義文件:
@interface CALayer : NSObject <NSCoding, CAMediaTiming>
{
@private
struct _CALayerIvars {
int32_t refcount;
uint32_t magic;
void *layer;
#if TARGET_OS_MAC && !TARGET_RT_64_BIT
void *unused1[8];
#endif
} _attr;
}
/** Layer creation and initialization. **/
+ (instancetype)layer;
/* The designated initializer. */
- (instancetype)init;
- (instancetype)initWithLayer:(id)layer;
- (nullable id)presentationLayer;
- (id)modelLayer;
+ (nullable id)defaultValueForKey:(NSString *)key;
+ (BOOL)needsDisplayForKey:(NSString *)key;
- (BOOL)shouldArchiveValueForKey:(NSString *)key;
@property CGRect bounds;
...```
可以看到比較多的屬性和方法,挑一些方法和屬性來(lái)介紹一下。
***
先看看以下兩個(gè)方法:
- (id)presentationLayer;
- (id)modelLayer;```
這兩個(gè)方法放在一起介紹,因?yàn)樗麄冎g是有關(guān)系。
調(diào)用- (id)modelLayer
返回的基本是當(dāng)前CALayer實(shí)例。其實(shí)這個(gè)就是你在代碼上修改的CALayer對(duì)象,比如像這樣:
CALayer *layer = [CALayer layer];
layer.position = CGPointMake(10, 10);
...```
這里你可能改了很多l(xiāng)ayer的其他屬性,無(wú)論改了多少,反正layer都幫你保存好了數(shù)據(jù)到堆里了。也就是說(shuō)修改的`layer.position = CGPointMake(10, 10)`存到了modelLayer上了。
調(diào)用`- (id)presentationLayer`同樣也會(huì)返回CALayer實(shí)例(注意當(dāng)被顯示出來(lái)之后再調(diào)用才不會(huì)nil),只不過(guò)這個(gè)實(shí)例不是你剛才在代碼上修改的那個(gè)layer了,而是屏幕上的layer的數(shù)據(jù),比如當(dāng)前屏幕上的`layer.position = CGPointMake(20, 20)`,這里從原來(lái)modelLayer的position{10, 10}變成了presentationLayer的position{20, 20}。
那么問(wèn)題來(lái)了:
+ 為什么會(huì)多一個(gè)presentationLayer出來(lái)呢?有什么作用呢?
先說(shuō)說(shuō)我們?cè)诖a上一般的做法。
比如我初始化了一個(gè)view出來(lái),大概是這樣的:
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];```
那么把他加到父view上去后,這個(gè)view就會(huì)顯示在父view的{(0, 0), (100, 100)}的位置了。這個(gè)很好理解,因?yàn)槲乙潭ㄒ粋€(gè)view就必須指明他的坐標(biāo)位置和大小。現(xiàn)在我覺(jué)得這個(gè)view要向右過(guò)一點(diǎn)會(huì)看好一些,那么我們代碼大概是這么做的:
CGRect frame = view.frame;
frame.origin = CGPointMake(10, 0);
view.frame = frame;```
然后在屏幕上看到現(xiàn)在view比沒(méi)修改之前向右移動(dòng)了10,然后我覺(jué)得又要再向右過(guò)一點(diǎn)才好看,我重復(fù)之前的操作,大概是這么做的:
CGRect frame = view.frame;
frame.origin = CGPointMake(20, 0);
view.frame = frame;```
再然后我繼續(xù)任性,重復(fù)每次增加10,去修改x,一共重復(fù)5次。最終修改成這樣:
CGRect frame = view.frame;
frame.origin = CGPointMake(50, 0);
view.frame = frame;```
好了,現(xiàn)在后頭想,如果我修改的速度足夠快,每次看到屏幕上的view都向右移動(dòng)10,最終移動(dòng)到50的位置上,那么這個(gè)view看起來(lái)好像是在做動(dòng)畫一樣的移動(dòng)到50的位置上一樣。
如果不明白上面表達(dá)的意思的話,我想說(shuō)前面的字就用來(lái)充字?jǐn)?shù)的,其實(shí)簡(jiǎn)單的說(shuō)一句:`小時(shí)候,是否有試過(guò)在書上畫個(gè)小動(dòng)物,每一頁(yè)都畫得比前一頁(yè)稍微有那么一點(diǎn)的不同,畫得頁(yè)數(shù)足夠多之后,快速翻頁(yè),可以看到這個(gè)畫出來(lái)的小動(dòng)物在動(dòng)了`。在網(wǎng)上找了個(gè)效果[翻頁(yè)動(dòng)畫](http://tieba.baidu.com/p/1948629478)
相信讀者也明白是什么的一個(gè)效果了。現(xiàn)在來(lái)打個(gè)比喻,如果這本書只有一頁(yè)畫了這個(gè)小動(dòng)物,你能看出他動(dòng)嗎?顯然不可以。那么很多張稍微不一樣的就能看出動(dòng)了,那是因?yàn)槟切┊嬅嬖谌四X中留下的殘影(如果不明白這個(gè)的話,估計(jì)要問(wèn)問(wèn)學(xué)物理的還是化學(xué)的同學(xué)了吧)。
>屏幕上是怎么翻頁(yè),才能讓人類感動(dòng)畫的呢?可以閱讀[動(dòng)畫基礎(chǔ)](http://www.baidu.com)
對(duì)于程序也是一樣,你看到一個(gè)view在動(dòng),那是這個(gè)view位置在不斷的稍微變化,在你眼睛里留下的殘影。剛才說(shuō)了如果這本書只有一頁(yè)的話根本看不出動(dòng)畫來(lái),就好比如果只是設(shè)置了`frame.origin = CGPointMake(50, 0);`你就只會(huì)看到view被迅移到了x為50的位置上了。那個(gè)剛才是從10,20,30,40,50這樣的移動(dòng),只要足夠快,就可以看到動(dòng)起來(lái)了。
好了,關(guān)于
+ 為什么會(huì)多一個(gè)presentationLayer出來(lái)呢?有什么作用呢?
這個(gè)問(wèn)題回答完了,就是因?yàn)樵谧鰟?dòng)畫的時(shí)候,需要把過(guò)渡的位置顯示出來(lái),而不是迅移,人類眼睛留下了殘影才可以看到有動(dòng)畫。所以需要一個(gè)presentationLayer來(lái)存放這些過(guò)渡的數(shù)據(jù),然后再這些過(guò)渡數(shù)據(jù)一個(gè)個(gè)渲染出來(lái)(其實(shí)就是每一幀)。那么可以看出來(lái)presentationLayer是為做動(dòng)畫服務(wù)的(其實(shí)有沒(méi)為其他服務(wù)我就不知道了)。`所以假如在做動(dòng)畫的時(shí)候,presentationLayer里面的值就是當(dāng)前屏幕的值;而modelLayer的值就是動(dòng)畫結(jié)束后的值`。
>不知道是否會(huì)有讀者認(rèn)為老是說(shuō)一下CALayer又說(shuō)一下UIView?說(shuō)的都亂了?可以閱讀[CALayer和UIView的關(guān)系](http://www.lxweimin.com/p/6351116c2d19)
***
再看這個(gè)方法:
- (BOOL)needsDisplayForKey:(NSString *)key;```
再看這些屬性:
@property CGRect bounds;
@property CGPoint position;
@property CGFloat zPosition;
@property CGPoint anchorPoint;
@property CGFloat anchorPointZ;
@property CGRect frame;```
關(guān)于這些屬性,其實(shí)官方文檔都說(shuō)得很清楚了,看以下這張圖吧:

左邊的是iOS的,上圖展現(xiàn)了bounds,frame,position,anchorPoint,可以看到黃色矩形的左上角x和y在坐標(biāo)系上是{40, 60},但實(shí)際bounds的x和y是{0, 0},那么可以得出一個(gè)結(jié)論是`bounds的x和y跟坐標(biāo)系位置無(wú)關(guān)`;又可以看到實(shí)際上`frame的x和y才是跟才是坐標(biāo)系的位置,bounds的width,height和frame的width,height是一樣的`;anchorPoint點(diǎn)怎么理解呢?比較多的文章可能說(shuō)拿釘子釘一塊板到墻上的例子,不過(guò)我想說(shuō),旋轉(zhuǎn)木馬沒(méi)玩過(guò)也看過(guò)吧,就是一直圍繞著中心轉(zhuǎn)啊轉(zhuǎn)的木馬,anchorPoint就是這個(gè)選擇木馬圍繞中心旋轉(zhuǎn)的點(diǎn),其實(shí)就是`圓心的圓點(diǎn)(一個(gè)無(wú)限多邊形的圖形其實(shí)就是圓),所以圖上的anchorPoint是{0.5, 0.5}剛好在中間(因?yàn)閍nchorPoint的x和y最大值分別都是1)`;那么知道了anchorPoint,position就好理解了,position就是`圓點(diǎn)在坐標(biāo)系上的坐標(biāo)`。
需要注意一下的是:`layer的frame比較特別,他是通過(guò)position, bounds,anchorPoint和transform共同計(jì)算出來(lái)的`。什么意思呢?意思就是你`修改position, bounds,anchorPoint和transform的值都會(huì)改變到frame`。在做動(dòng)畫的時(shí)候就要注意了,改變position, bounds,anchorPoint和transform會(huì)導(dǎo)致frame的改變,可能就會(huì)出現(xiàn)你不想出現(xiàn)的情況,比如layer突然向上,下,左,右迅移了。
然后再來(lái)兩張圖:


第一張圖是一個(gè)UIView靜止的時(shí)候,第二張圖是UIView在做旋轉(zhuǎn)的時(shí)候,可以發(fā)現(xiàn)他們的frame不一樣了,明顯第二張圖變大了。這是因?yàn)檫@個(gè)UIView要保持矩形所以旋轉(zhuǎn)的時(shí)候就frame變大了。