Auto Layout 原理
Auto Layout是一種全新的布局方式,它采用一系列約束(constraints)來實現(xiàn)自動布局工猜,當(dāng)你的屏幕尺寸發(fā)生變化或者屏幕發(fā)生旋轉(zhuǎn)時米诉,可以不用添加代碼來保持原有布局不變,實現(xiàn)視圖的自動布局篷帅。
所謂約束史侣,通常是定義了兩個視圖之間的關(guān)系(當(dāng)然你也可以一個視圖自己跟自己設(shè)定約束)拴泌。如下圖就是一個約束的例子,當(dāng)然要確定一個視圖的位置惊橱,跟基于frame一樣蚪腐,也是需要確定視圖的橫縱坐標(biāo)以及寬度和高度的,只是税朴,這個橫縱坐標(biāo)和寬度高度不再是寫死的數(shù)值削茁,而是根據(jù)約束計算得來,從而達到自動布局的效果掉房。
UIView之drawRect: & layoutSubviews的作用和機制
drawRect 調(diào)用機制
1茧跋、調(diào)用時機:loadView ->ViewDidload ->drawRect:
2、如果在UIView初始化時沒有設(shè)置rect大小卓囚,將直接導(dǎo)致drawRect:不被自動調(diào)用瘾杭。
3、通過設(shè)置contentMode屬性值為UIViewContentModeRedraw哪亿。那么將在每次設(shè)置或更改frame
的時候自動調(diào)用drawRect:
粥烁。
4、直接調(diào)用setNeedsDisplay蝇棉,或者setNeedsDisplayInRect:觸發(fā)drawRect:讨阻,但是有個前提條件是:view當(dāng)前的rect不能為nil
5、該方法在調(diào)用sizeThatFits后被調(diào)用篡殷,所以可以先調(diào)用sizeToFit計算出size钝吮。然后系統(tǒng)自動調(diào)用drawRect:方法。
這里簡單說一下sizeToFit和sizeThatFit:
sizeToFit:會計算出最優(yōu)的 size 而且會改變自己的size
sizeThatFits:會計算出最優(yōu)的 size 但是不會改變 自己的 size
注意事項
1板辽、若使用UIView繪圖奇瘦,只能在drawRect:方法中獲取相應(yīng)的contextRef并繪圖。如果在其他方法中獲取到一個invalidate的ref保存下來劲弦,在drawRect中并不能用于畫圖耳标。等到在這里調(diào)用時,可能當(dāng)前上下文環(huán)境已經(jīng)變化邑跪。
2次坡、若使用CALayer繪圖,只能在drawInContext: 中(類似于drawRect)繪制画畅,或者在delegate中的相應(yīng)方法繪制砸琅。同樣也是調(diào)用setNeedDisplay等間接調(diào)用以上方法。
3夜赵、若要實時畫圖明棍,不能使用gestureRecognizer,只能使用touchbegan等方法來掉用setNeedsDisplay實時刷新屏幕寇僧。
4摊腋、UIImageView繼承自UIView,但是UIImageView能不重寫drawRect方法用于實現(xiàn)自定義繪圖沸版。具體原因如下:
Apple在文檔中指出:UIImageView是專門為顯示圖片做的控件,用了最優(yōu)顯示技術(shù)兴蒸,是不讓調(diào)用darwrect方法视粮, 要調(diào)用這個方法,只能從uiview里重寫橙凳。
layoutSubviews
這個方法是用來對subviews重新布局
蕾殴,默認(rèn)沒有做任何事情,需要子類進行重寫岛啸。
當(dāng)我們在某個類的內(nèi)部調(diào)整子視圖位置時钓觉,需要調(diào)用。
反過來的意思就是說:如果你想要在外部設(shè)置subviews的位置坚踩,就不要重寫荡灾。
①、- (void)layoutSubviews;
對subview重新布局
②瞬铸、- (void)setNeedsLayout;
將視圖標(biāo)記為需要重新布局批幌, 這個方法會在系統(tǒng)runloop的下一個周期自動調(diào)用layoutSubviews。
③嗓节、- (void)layoutIfNeeded;
如果有需要刷新的標(biāo)記
荧缘,立即調(diào)用layoutSubviews進行布局(如果沒有標(biāo)記,不會調(diào)用layoutSubviews)這里注意一個點:標(biāo)記拦宣,沒有標(biāo)記截粗,即使我們掉了該函數(shù)也不起作用
。
如果要立即刷新恢着,要先調(diào)用[view setNeedsLayout]桐愉,把標(biāo)記設(shè)為需要布局财破,然后馬上調(diào)用[view layoutIfNeeded]掰派,實現(xiàn)布局.
在視圖第一次顯示之前,標(biāo)記總是“需要刷新”的左痢,可以直接調(diào)用[view layoutIfNeeded]
這里有必要描述下三者之間的關(guān)系:
在沒有外界干預(yù)的情況下靡羡,一個view的frame或者bounds發(fā)生變化時,系統(tǒng)會先去標(biāo)記flag這個view,等下一次渲染時機到來時(也就是runloop的下一次循環(huán))俊性,會去按照最新的布局去重新布局視圖略步。
setNeedLayout
就是給這個view添加一個標(biāo)記,告訴系統(tǒng)下一次渲染時機需要重新布局這個視圖定页。
layoutIfNeed
就是告訴系統(tǒng)趟薄,如果已經(jīng)設(shè)置了flag,那不用等待下個渲染時機到來典徊,立即重新渲染杭煎。前提是設(shè)置了flag恩够。
而layoutSubviews
則是由系統(tǒng)去調(diào)用,不需要我們主動調(diào)用羡铲,我們只需要調(diào)用layoutIfNeed
蜂桶,告訴系統(tǒng)是否立即執(zhí)行重新布局的操作。
layoutSubviews調(diào)用時機
結(jié)論是經(jīng)過搜索得到的也切,基于此筆者進行了驗證扑媚,并得到了些結(jié)果:
1、init初始化不會觸發(fā)layoutSubviews雷恃。
2疆股、addSubview會觸發(fā)layoutSubviews。(當(dāng)然這里frame為0倒槐,是不會調(diào)用的押桃,同上面的drawrect:一樣)
3、設(shè)置view的Frame會觸發(fā)layoutSubviews导犹,(當(dāng)然前提是frame的值設(shè)置前后發(fā)生了變化唱凯。)
4、滾動一個UIScrollView會觸發(fā)layoutSubviews谎痢。
5磕昼、旋轉(zhuǎn)屏幕會觸發(fā)父UIView上的layoutSubviews事件。(這個我們開發(fā)中會經(jīng)常遇到节猿,比如屏幕旋轉(zhuǎn)時票从,為了界面美觀我們需要修改子view的frame,那就會在layoutSubview中做相應(yīng)的操作)
6滨嘱、改變一個UIView大小的時候也會觸發(fā)父UIView上的layoutSubviews事件峰鄙。
7、直接調(diào)用setLayoutSubviews太雨。(Apple是不建議這么做的)
這里需要補充一點:
layoutSubview是布局相關(guān)吟榴,而drawRect則是負(fù)責(zé)繪制。因此從調(diào)用時序上來講囊扳,layoutSubviews要早于drawRect:函數(shù)吩翻。