iOS-UIView和CALayer的關(guān)系

1.響應(yīng)事件

首先從繼承關(guān)系來(lái)看而钞,UIView繼承于UIResponse仪壮,而CALayer繼承于NSObject蒲稳。UIKit使用UIResponse作為響應(yīng)對(duì)象瞭郑,來(lái)響應(yīng)系統(tǒng)傳遞的事件并進(jìn)行處理辜御。所以UIView可以響應(yīng)事件,而CALayer不具備響應(yīng)事件的能力屈张。CALayer是QuartzCore中的類(lèi)擒权,負(fù)責(zé)繪制內(nèi)容

下面列舉一些處理觸摸事件的接口:

-(void)touchesBegan:(NSSet<UITouch*>*)touches withEvent:(nullable UIEvent*)event

-(void)touchesMoved:(NSSet<UITouch*>*)touches withEvent:(nullable UIEvent*)event

-(void)touchesEnded:(NSSet<UITouch*>*)touches withEvent:(nullable UIEvent*)event

-(void)touchesCancelled:(NSSet<UITouch*>*)touches withEvent:(nullable UIEvent*)event

-(void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch*>*)touchesNS_AVAILABLE_IOS(9_1)

并且UIView中提供了以下兩個(gè)方法阁谆,來(lái)進(jìn)行iOS中事件的響應(yīng)和傳遞:

-(nullable UIView*)hitTest:(CGPoint)point withEvent:(nullable UIEvent*)event

-(BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent*)event

2.初始化和Frame

一個(gè) Layer 的 frame 是由它的 anchorPoint,position,bounds,和 transform 共同決定的碳抄,而一個(gè) View 的 frame 只是簡(jiǎn)單的返回 Layer的 frame,同樣 View 的 center和 bounds 也是返回 Layer 的一些屬性场绿。為了一探究竟剖效,做如下測(cè)試。

自定義兩個(gè)類(lèi)MyView和MyLayer焰盗,分別繼承于UIView和CALayer贱鄙。

在MyView中重寫(xiě)以下方法:

- (instancetype)init {

? ? self= [superinit];

? ? if(self) {

? ? ? ? NSLog(@"============ MyView init!");

? ? }

? ? return self;

}

+ (Class)layerClass {

? ? return[MyLayerclass];

}

- (void)setFrame:(CGRect)frame {

? ? [supersetFrame:frame];

}

- (void)setCenter:(CGPoint)center {

? ? [supersetCenter:center];

}

- (void)setBounds:(CGRect)bounds {

? ? [supersetBounds:bounds];

}

在MyLayer中重寫(xiě)以下方法:

- (instancetype)init

{

? ? self= [super init];

? ? if(self) {

? ? ? ? NSLog(@"============= MyLayer init!");

? ? }

? ? return self;

}

+ (Class)layerClass {

? ? return [MyLayer class];

}

- (void)setFrame:(CGRect)frame {

? ? [super setFrame:frame];

}

- (void)setPosition:(CGPoint)position {

? ? [super setPosition:position];

}

- (void)setBounds:(CGRect)bounds {

? ? [super setBounds:bounds];

}

在兩個(gè)類(lèi)的初始化方法中都打下斷點(diǎn)調(diào)用:

可以看到在創(chuàng)建MyView時(shí)會(huì)調(diào)用私有方法 [UIView _createLayerWithFrame:] 創(chuàng)建CALayer。然后在創(chuàng)建View時(shí)在View和Layer的Frame相關(guān)方法中都加上斷點(diǎn)姨谷,可以看到調(diào)用順序如下:

[MyLayer setBounds:]

[MyView setFrame:]

[MyLayer setFrame:]

[MyLayer setPosition:]

[MyLayer setBounds:]

由此看到創(chuàng)建時(shí)只調(diào)用了Layer的設(shè)置尺寸和位置逗宁,并沒(méi)有調(diào)用View的setCenter:和setBounds:方法。

然后我發(fā)現(xiàn)當(dāng)我修改了 view的bounds.size或者bounds.origin的時(shí)候也只會(huì)調(diào)用上邊 Layer的一些方法梦湘。所以我大膽的猜一下瞎颗,View 的 Center 和 Bounds 只是直接返回layer 對(duì)應(yīng)的 Position 和 Bounds.

View中frame getter方法件甥,bounds和center,UIView并沒(méi)有做什么工作哼拔;它只是簡(jiǎn)單的各自調(diào)用它底層的CALayer的frame引有,bounds和position方法。

3.UIView主要是對(duì)顯示內(nèi)容的管理而CALayer負(fù)責(zé)顯示內(nèi)容的繪制

在UIView和CALayer分別重寫(xiě)父類(lèi)方法:

在MyView重寫(xiě)drawRect:

- (void)drawRect:(CGRect)rect {

? ? [super drawRect:rect];

}

在MyLayer重寫(xiě)display:

- (void)display {

? ? [super display];

}

在兩個(gè)方法中打斷點(diǎn)并執(zhí)行倦逐,得到如下結(jié)果:


可以看到UIView是CALayer的CALayerDelegate譬正,由此可以推測(cè)是在代理方法內(nèi)部[UIView(CALayerDelegate) drawLayer:inContext]調(diào)用UIView的drawRect方法,從而繪制出了UIView的內(nèi)容檬姥。

4.隱式動(dòng)畫(huà)

每個(gè)view都有一個(gè)layer曾我,但是也有一些不依附view單獨(dú)存在的layer,如CAShapelayer健民。它們不需要附加到 view 上就可以在屏幕上顯示內(nèi)容抒巢。

基本上你改變一個(gè)單獨(dú)的 layer 的任何屬性的時(shí)候,都會(huì)觸發(fā)一個(gè)從舊的值過(guò)渡到新值的簡(jiǎn)單動(dòng)畫(huà)(這就是所謂的隱式動(dòng)畫(huà))秉犹。然而蛉谜,如果你改變的是 view 中 layer 的同一個(gè)屬性,它只會(huì)從這一幀直接跳變到下一幀崇堵。盡管兩種情況中都有 layer型诚,但是當(dāng) layer 附加在 view 上時(shí),它的默認(rèn)的隱式動(dòng)畫(huà)的 layer 行為就不起作用了鸳劳。

在 Core Animation 編程指南的 “How to Animate Layer-Backed Views” 中俺驶,對(duì)為什么會(huì)這樣做出了一個(gè)解釋?zhuān)?/p>

UIView默認(rèn)情況下禁止了layer動(dòng)畫(huà),但是在animation block中又重新啟用了它們棍辕。

是因?yàn)槿魏慰蓜?dòng)畫(huà)的 layer 屬性改變時(shí)暮现,layer都會(huì)尋找并運(yùn)行合適的action來(lái)實(shí)行這個(gè)改變。在Core Animation的專(zhuān)業(yè)術(shù)語(yǔ)中就把這樣的動(dòng)畫(huà)統(tǒng)稱(chēng)為動(dòng)作 (action楚昭,或者CAAction)栖袋。

layer通過(guò)向它的delegate發(fā)送actionForLayer:forKey:消息來(lái)詢問(wèn)提供一個(gè)對(duì)應(yīng)屬性變化的action。delegate可以通過(guò)返回以下三者之一來(lái)進(jìn)行響應(yīng):

它可以返回一個(gè)動(dòng)作對(duì)象抚太,這種情況下layer將使用這個(gè)動(dòng)作塘幅。

它可以返回一個(gè)nil, 這樣layer就會(huì)到其他地方繼續(xù)尋找尿贫。

它可以返回一個(gè)NSNull對(duì)象电媳,告訴layer這里不需要執(zhí)行一個(gè)動(dòng)作,搜索也會(huì)就此停止庆亡。

當(dāng)layer在背后支持一個(gè)view的時(shí)候匾乓,view就是它的delegate。

5.單一職責(zé)

UIView負(fù)責(zé)用戶的響應(yīng)操作又谋,CALayer負(fù)責(zé)繪制拼缝,就像一個(gè)類(lèi)似公司的框架一樣娱局,把如同公司職員的各個(gè)功能層級(jí)組織起來(lái),然后各司其職咧七。

機(jī)制與策略分離

Unix內(nèi)核設(shè)計(jì)的一個(gè)主要思想是——提供(Mechanism)機(jī)制而不是策略(Policy)衰齐。編程問(wèn)題都可以抽離出機(jī)制和策略部分。機(jī)制一旦實(shí)現(xiàn)继阻,就會(huì)很少更改耻涛,但策略會(huì)經(jīng)常得到優(yōu)化。例如原子可以看做是機(jī)制瘟檩,而各種原子的組成就是一種策略抹缕。CALayer也可以看做是一種機(jī)制,提供圖層繪制芒帕,你們可以翻開(kāi)CALayer的頭文件看看歉嗓,基本上是沒(méi)怎么變過(guò)的丰介,而UIView可以看做是策略背蟆,變動(dòng)很多。越是底層哮幢,越是機(jī)制带膀,越是機(jī)制就越是穩(wěn)定。機(jī)制與策略分離橙垢,可以使得需要修改的代碼更少垛叨,特別是底層代碼,這樣可以提高系統(tǒng)的穩(wěn)定性柜某。

更多的不可變

穩(wěn)定給你的是什么感覺(jué)嗽元?堅(jiān)固?不可形變喂击?穩(wěn)定其實(shí)就是不可變剂癌。一個(gè)系統(tǒng)不可變的東西越多,越是穩(wěn)定翰绊。所以機(jī)制恰是滿足這個(gè)不可變的因素的佩谷。構(gòu)建一個(gè)系統(tǒng)有一個(gè)指導(dǎo)思想就是盡量抽取不可變的東西和可變的東西分離。水是成不了萬(wàn)丈高樓的监嗜,堅(jiān)固的混凝土才可以谐檀。更少的修改,意味著更少的bug的幾率裁奇。

各司其職

即使能力再大也不能把說(shuō)有事情都干了桐猬,萬(wàn)一哪一天不行了呢,那就是突然什么都不能干了刽肠。所以僅僅是基于分散風(fēng)險(xiǎn)原則也不應(yīng)該出現(xiàn)全能類(lèi)课幕。各司其職厦坛,相互合作,把可控粒度降到最低乍惊,這樣也可以是系統(tǒng)更穩(wěn)定杜秸,更易修改。

漏的更少

接口應(yīng)該面向大眾的润绎,按照八二原則撬碟,其實(shí)20%的接口就可以滿足80%的需求,剩下的80%應(yīng)該隱藏在背后莉撇。因?yàn)槁┑纳倏偸前踩哪馗颍皇菃帷JO碌?0%專(zhuān)家接口可以隱藏與深層次棍郎。比如UIView遮蔽了大部分的CALayer接口其障,抽取構(gòu)造出更易用的frame和動(dòng)畫(huà)實(shí)現(xiàn),這樣上手更容易涂佃。

總結(jié):

1.view負(fù)責(zé)了與人的動(dòng)作交互以及對(duì)layer的管理励翼,layer則負(fù)責(zé)了所有能讓人看到的東西。

2.每個(gè) UIView 內(nèi)部都有一個(gè) CALayer 在背后提供內(nèi)容的繪制和顯示辜荠,并且 UIView 的尺寸樣式都由內(nèi)部的 Layer 所提供汽抚。兩者都有樹(shù)狀層級(jí)結(jié)構(gòu),layer 內(nèi)部有SubLayers伯病,View 內(nèi)部有SubViews.但是 Layer 比 View 多了個(gè)AnchorPoint造烁。

3.在 View顯示的時(shí)候,UIView 做為 Layer 的CALayerDelegate,View 的顯示內(nèi)容取決于內(nèi)部的 CALayer 的?display午笛。

4.CALayer 是默認(rèn)修改屬性支持隱式動(dòng)畫(huà)的惭蟋,在給 UIView 的 Layer 做動(dòng)畫(huà)的時(shí)候,View 作為 Layer 的代理药磺,Layer 通過(guò)actionForLayer:forKey:向 View請(qǐng)求相應(yīng)的action(動(dòng)畫(huà)行為)告组。

5.layer 內(nèi)部維護(hù)著三分layer tree,分別是presentLayer Tree(動(dòng)畫(huà)樹(shù)),modeLayer Tree(模型樹(shù)),Render Tree(渲染樹(shù)),在做 iOS動(dòng)畫(huà)的時(shí)候,我們修改動(dòng)畫(huà)的屬性与涡,在動(dòng)畫(huà)的其實(shí)是 Layer 的 presentLayer的屬性值,而最終展示在界面上的其實(shí)是提供 View的modelLayer惹谐。

6.單一職責(zé)的設(shè)計(jì)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末驼卖,一起剝皮案震驚了整個(gè)濱河市氨肌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌酌畜,老刑警劉巖怎囚,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡恳守,警方通過(guò)查閱死者的電腦和手機(jī)考婴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)催烘,“玉大人沥阱,你說(shuō)我怎么就攤上這事∫寥海” “怎么了考杉?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)舰始。 經(jīng)常有香客問(wèn)我崇棠,道長(zhǎng),這世上最難降的妖魔是什么丸卷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任枕稀,我火速辦了婚禮,結(jié)果婚禮上谜嫉,老公的妹妹穿的比我還像新娘萎坷。我一直安慰自己,他們只是感情好骄恶,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布食铐。 她就那樣靜靜地躺著匕垫,像睡著了一般僧鲁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上象泵,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天寞秃,我揣著相機(jī)與錄音,去河邊找鬼偶惠。 笑死春寿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的忽孽。 我是一名探鬼主播绑改,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼兄一!你這毒婦竟也來(lái)了厘线?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤出革,失蹤者是張志新(化名)和其女友劉穎造壮,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體骂束,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡耳璧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年成箫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旨枯。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蹬昌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出攀隔,到底是詐尸還是另有隱情凳厢,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布竞慢,位于F島的核電站先紫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏筹煮。R本人自食惡果不足惜遮精,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望败潦。 院中可真熱鬧本冲,春花似錦、人聲如沸劫扒。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)沟饥。三九已至添怔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贤旷,已是汗流浹背广料。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留幼驶,地道東北人艾杏。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像盅藻,于是被迫代替她去往敵國(guó)和親购桑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359