【IOS 知識點】 視圖&圖像相關(guān)

Auto Layout 原理

Auto Layout是一種全新的布局方式,它采用一系列約束(constraints)來實現(xiàn)自動布局,當你的屏幕尺寸發(fā)生變化或者屏幕發(fā)生旋轉(zhuǎn)時,可以不用添加代碼來保持原有布局不變,實現(xiàn)視圖的自動布局。

所謂約束,通常是定義了兩個視圖之間的關(guān)系(當然你也可以一個視圖自己跟自己設(shè)定約束)。如下圖就是一個約束的例子,當然要確定一個視圖的位置,跟基于frame一樣,也是需要確定視圖的橫縱坐標以及寬度和高度的,只是,這個橫縱坐標和寬度高度不再是寫死的數(shù)值,而是根據(jù)約束計算得來,從而達到自動布局的效果。

UIView之drawRect: & layoutSubviews的作用和機制

drawRect 調(diào)用機制

1、調(diào)用時機:loadView ->ViewDidload ->drawRect:
2、如果在UIView初始化時沒有設(shè)置rect大小,將直接導致drawRect:不被自動調(diào)用。
3、通過設(shè)置contentMode屬性值為UIViewContentModeRedraw。那么將在每次設(shè)置或更改frame的時候自動調(diào)用drawRect:。
4、直接調(diào)用setNeedsDisplay,或者setNeedsDisplayInRect:觸發(fā)drawRect:,但是有個前提條件是:view當前的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)用時,可能當前上下文環(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重新布局,默認沒有做任何事情,需要子類進行重寫。
當我們在某個類的內(nèi)部調(diào)整子視圖位置時,需要調(diào)用。
反過來的意思就是說:如果你想要在外部設(shè)置subviews的位置,就不要重寫。

①、- (void)layoutSubviews;
對subview重新布局
②、- (void)setNeedsLayout;
將視圖標記為需要重新布局, 這個方法會在系統(tǒng)runloop的下一個周期自動調(diào)用layoutSubviews。
③、- (void)layoutIfNeeded;
如果有需要刷新的標記立即調(diào)用layoutSubviews進行布局(如果沒有標記,不會調(diào)用layoutSubviews)這里注意一個點:標記,沒有標記,即使我們掉了該函數(shù)也不起作用。
如果要立即刷新,要先調(diào)用[view setNeedsLayout],把標記設(shè)為需要布局,然后馬上調(diào)用[view layoutIfNeeded],實現(xiàn)布局.
在視圖第一次顯示之前,標記總是“需要刷新”的,可以直接調(diào)用[view layoutIfNeeded]

這里有必要描述下三者之間的關(guān)系:
在沒有外界干預的情況下,一個view的frame或者bounds發(fā)生變化時,系統(tǒng)會先去標記flag這個view,等下一次渲染時機到來時(也就是runloop的下一次循環(huán)),會去按照最新的布局去重新布局視圖。
setNeedLayout就是給這個view添加一個標記,告訴系統(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。(當然這里frame為0,是不會調(diào)用的,同上面的drawrect:一樣)
3、設(shè)置view的Frame會觸發(fā)layoutSubviews,(當然前提是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則是負責繪制。因此從調(diào)用時序上來講,layoutSubviews要早于drawRect:函數(shù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言: 最近公司項目不怎么忙, 閑暇時間把iOS 在面試中可能會遇到的問題整理了一番, 一部分題目是自己面試遇到...
    Leon_520閱讀 9,877評論 3 45
  • 這部分主要講一下UI視圖和圖像相關(guān)的技術(shù)點,大致包括以下內(nèi)容 UI事件傳遞&響應(yīng) UI圖像顯示原理 UI卡頓,掉幀...
    theonelgq閱讀 456評論 0 1
  • 可否使用 == 來判斷兩個NSString類型的字符串是否相同?為什么? 不能。==判斷的是兩個變量的值的內(nèi)存地址...
    漸z閱讀 677評論 0 0
  • layoutSubviews 這個方法,默認沒有做任何事情,需要子類進行重寫。 (This method) Lay...
    我是不是叫沒煩惱閱讀 746評論 0 0
  • 原文出自別人之手,只做個人記錄而已! Layout相關(guān)方法小結(jié) - (CGSize)sizeThatFits:(C...
    安靜的抉擇閱讀 342評論 0 0

友情鏈接更多精彩內(nèi)容