LayoutSubview使用中的坑
我們調(diào)用layoutsubview去刷新布局的方法是 [self.button setNeedsLayout]; ?這個(gè)方法是異步的勾缭,我們來看一下打印結(jié)果:
為什么是異步的呢?
因?yàn)閞unloop咽筋,這里涉及到runloop的源碼分析弊仪,這篇文章暫不展開分析但绕,后面會(huì)寫一篇關(guān)于runloop源碼分析的文章而柑。這里只需要知道:刷新布局的操作被標(biāo)記苟耻,被runloop放到一下個(gè)循環(huán)中執(zhí)行(試想一下蛤育,如果同步宛官,那么我有多個(gè)view的setNeedsLayout要執(zhí)行的情況下,性能開銷相對(duì)比較大)runloop在下一個(gè)循環(huán)中處理所有的本次循環(huán)標(biāo)記的刷新布局操作瓦糕。
如何同步底洗?
setNeedsLayout
layoutIfNeeded
只需要這兩句一起執(zhí)行
drawRect分析
CGContextRef context = UIGraphicsGetCurrentContext();
當(dāng)我們?cè)赿rawrect中想要繪畫內(nèi)容時(shí),首先會(huì)獲取我們常說的“上下文”
那么這個(gè)上下文是什么呢咕娄?
這里我們先來看一下這兩句代碼
UIGraphicsPopContext();
看一下這句代碼的描述
從堆棧頂部刪除當(dāng)前圖形上下文亥揖,恢復(fù)先前的上下文。
使用此功能可以平衡對(duì)UIGraphicsPushContext函數(shù)的調(diào)用圣勒。
可以從應(yīng)用程序的任何線程調(diào)用此函數(shù)费变。
我們的圖形上下文,是存放在系統(tǒng)的一個(gè)專門用來存放上下的堆棧中圣贸,系統(tǒng)在drawrect方法中挚歧,會(huì)將此view的上下文推到這個(gè)堆棧中。所以吁峻,在drawrect中滑负,獲取當(dāng)前上下文,可以獲取到和這個(gè)view所關(guān)聯(lián)的上下文用含,繼而操作矮慕。我們做一個(gè)小實(shí)驗(yàn):
可以看到,只有在view的drawrect方法中啄骇,存放上下文的棧才會(huì)有當(dāng)前上下文痴鳄,也證實(shí)了?系統(tǒng)在drawrect方法中,會(huì)將此view的上下文推到這個(gè)堆棧中 ? 這個(gè)結(jié)論
UIGraphicsPushContext(nil);
這句代碼缸夹,則是將某個(gè)上下文痪寻,推到存放上下文的棧里。
正常情況下虽惭,我們不會(huì)調(diào)用這兩句代碼槽华,在drawrect中我們就可以獲取到當(dāng)前上下文,不會(huì)pop / push
那么context 上下文趟妥,影響的是什么呢?
影響的是CALayer
?我們?cè)谏舷挛闹械牟僮饔度兀紩?huì)渲染到當(dāng)然view的layer中
延伸1:view和layer的關(guān)系是什么
簡(jiǎn)而言之:我們屏幕上所看到的視覺效果披摄,是CAlayer所展現(xiàn)出來的亲雪。而view只是負(fù)責(zé)管理CAlayer的,UIView是繼承UIResponder的疚膊,是用來負(fù)責(zé)響應(yīng)交互的义辕。
延伸2:IB_DESIGNBLE
一個(gè)有意思的可視化:
可以在xib中看到所修飾的view的當(dāng)前calayer的層次,也就是說在這個(gè)view上加個(gè)button寓盗,再在button的drawrect中繪制灌砖,是看不到的。