今天單純說(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)畫(huà)一樣的移動(dòng)到50的位置上一樣。
如果不明白上面表達(dá)的意思的話于游,我想說(shuō)前面的字就用來(lái)充字?jǐn)?shù)的毁葱,其實(shí)簡(jiǎn)單的說(shuō)一句:`小時(shí)候,是否有試過(guò)在書(shū)上畫(huà)個(gè)小動(dòng)物贰剥,每一頁(yè)都畫(huà)得比前一頁(yè)稍微有那么一點(diǎn)的不同倾剿,畫(huà)得頁(yè)數(shù)足夠多之后,快速翻頁(yè)蚌成,可以看到這個(gè)畫(huà)出來(lái)的小動(dòng)物在動(dòng)了`前痘。在網(wǎng)上找了個(gè)效果[翻頁(yè)動(dòng)畫(huà)](http://tieba.baidu.com/p/1948629478)
相信讀者也明白是什么的一個(gè)效果了。現(xiàn)在來(lái)打個(gè)比喻担忧,如果這本書(shū)只有一頁(yè)畫(huà)了這個(gè)小動(dòng)物芹缔,你能看出他動(dòng)嗎?顯然不可以涵妥。那么很多張稍微不一樣的就能看出動(dòng)了乖菱,那是因?yàn)槟切┊?huà)面在人腦中留下的殘影(如果不明白這個(gè)的話,估計(jì)要問(wèn)問(wèn)學(xué)物理的還是化學(xué)的同學(xué)了吧)蓬网。
>屏幕上是怎么翻頁(yè)窒所,才能讓人類感動(dòng)畫(huà)的呢?可以閱讀[動(dòng)畫(huà)基礎(chǔ)](http://www.baidu.com)
對(duì)于程序也是一樣帆锋,你看到一個(gè)view在動(dòng)吵取,那是這個(gè)view位置在不斷的稍微變化,在你眼睛里留下的殘影锯厢。剛才說(shuō)了如果這本書(shū)只有一頁(yè)的話根本看不出動(dòng)畫(huà)來(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)畫(huà)的時(shí)候茵臭,需要把過(guò)渡的位置顯示出來(lái),而不是迅移舅世,人類眼睛留下了殘影才可以看到有動(dòng)畫(huà)旦委。所以需要一個(gè)presentationLayer來(lái)存放這些過(guò)渡的數(shù)據(jù),然后再這些過(guò)渡數(shù)據(jù)一個(gè)個(gè)渲染出來(lái)(其實(shí)就是每一幀)歇终。那么可以看出來(lái)presentationLayer是為做動(dòng)畫(huà)服務(wù)的(其實(shí)有沒(méi)為其他服務(wù)我就不知道了)社证。`所以假如在做動(dòng)畫(huà)的時(shí)候,presentationLayer里面的值就是當(dāng)前屏幕的值评凝;而modelLayer的值就是動(dòng)畫(huà)結(jié)束后的值`追葡。
>不知道是否會(huì)有讀者認(rèn)為老是說(shuō)一下CALayer又說(shuō)一下UIView?說(shuō)的都亂了奕短?可以閱讀[CALayer和UIView的關(guān)系](http://www.reibang.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)畫(huà)的時(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變大了。