layout相關(guān)的方法

- (void)layoutSubviews;
- (void)setNeedsLayout;
- (void)layoutIfNeeded;
- (void)drawRect;
- (void)setNeedsDisplay;

1.layoutSubviews

  • 此方法默認(rèn)執(zhí)行你在所有子視圖中已經(jīng)明確設(shè)置的所有尺寸和位置約束。
  • 必要時(shí)可以在子類中重寫這個(gè)方法,以實(shí)現(xiàn)更加精細(xì)的子視圖布局。只要子視圖的自動(dòng)尺寸調(diào)整和基于約束系統(tǒng)行為不能提供你想要的效果,你就應(yīng)該重寫這個(gè)方法,直接設(shè)置子視圖的frame(來實(shí)現(xiàn)你想要的效果)。
  • 你不應(yīng)該直接調(diào)用此方法,如果想強(qiáng)制更新布局,要調(diào)用 setNeedsLayout 方法,但該方法不會(huì)立即重繪視圖(drawing) 。如果想立即更新視圖布局(layout) ,請(qǐng)調(diào)用 layoutIfNeeded 方法。

什么時(shí)候系統(tǒng)會(huì)執(zhí)行l(wèi)ayoutSubviews

官方文檔提到了layoutSubviews不是供用戶來調(diào)用的,而是系統(tǒng)自動(dòng)調(diào)用的,我們能做的就是重寫該方法。那么什么時(shí)候系統(tǒng)會(huì)調(diào)用layoutSubviews方法呢?這個(gè)方法,默認(rèn)沒有做任何事情,需要子類進(jìn)行重寫

在以下情況下會(huì)被調(diào)用:

1>、init初始化不會(huì)觸發(fā)layoutSubviews。
2>、addSubview會(huì)觸發(fā)layoutSubviews。
3>、設(shè)置view的Frame會(huì)觸發(fā)layoutSubviews,當(dāng)然前提是frame的值設(shè)置前后發(fā)生了變化。
4>、滾動(dòng)一個(gè)UIScrollView會(huì)觸發(fā)layoutSubviews。
5>、旋轉(zhuǎn)Screen會(huì)觸發(fā)父UIView上的layoutSubviews事件。
6>、改變一個(gè)UIView大小的時(shí)候也會(huì)觸發(fā)父UIView上的layoutSubviews事件。
7>、setNeedsLayout方法并不會(huì)立即刷新,立即刷新需要調(diào)用layoutIfNeeded方法。

在蘋果的官方文檔中強(qiáng)調(diào):
You should override this method only if the autoresizing behaviors of the subviews do not offer the behavior you want.
layoutSubviews, 當(dāng)我們?cè)谀硞€(gè)類的內(nèi)部調(diào)整子視圖位置時(shí),需要調(diào)用。
反過來的意思就是說:如果你想要在外部設(shè)置subviews的位置,就不要重寫。

setNeedsLayout

  • 在當(dāng)前布局周期發(fā)送setNeedsLayout消息是無效的,直到下一個(gè)布局周期才會(huì)觸發(fā)布局更新。
  • 當(dāng)你想要調(diào)整子視圖的布局時(shí),你可以在應(yīng)用的主線程調(diào)用該方法。這個(gè)方法將記錄布局請(qǐng)求,并立即返回。由于該方法不強(qiáng)制立即更新,而是等到下一個(gè)更新周期,所以你可以在當(dāng)前的無效周期內(nèi)添加多個(gè)多個(gè)視圖的布局,等到下一個(gè)周期同一更新。這么做通??梢垣@得更好的性能。
作用:告之view,需要重新布局,在未來某個(gè)時(shí)間點(diǎn)系統(tǒng)異步觸發(fā)布局方法,且標(biāo)記view.subViews需要重新布局。這個(gè)方法使用后,view不會(huì)立即刷新,但layoutSubviews{}一定會(huì)被調(diào)用.

layoutIfNeeded

  • 立即布局子視圖
  • 使用這個(gè)方法可以在系統(tǒng)繪制視圖之前強(qiáng)制(重新)布局子視圖。這個(gè)方法將從當(dāng)前視圖開始布局當(dāng)前視圖樹之下的所有子視圖。
如果:有需要刷新的標(biāo)記,立即調(diào)用layoutSubviews進(jìn)行布局(如果沒有標(biāo)記,不會(huì)調(diào)用layoutSubviews)

注: layoutSubviews 方法是用來設(shè)定subview的位置的方法, 是不能手動(dòng)調(diào)用的。只能通過調(diào)用setNeedsLayout 方法,來讓系統(tǒng)自動(dòng)調(diào)用layoutSubviews方法。
例如:

[UIView animateWithDuration:5.0 animations:^{
        _left_constrait.constant = 100;
        //[self.view layoutIfNeeded];
    }];

在按鈕中執(zhí)行這句代碼,發(fā)現(xiàn)label動(dòng)畫并沒有執(zhí)行,其實(shí)這個(gè)約束只是執(zhí)行了setNeedsLayout標(biāo)記了需要重新布局,但是沒有立即執(zhí)行。所以我們需要在動(dòng)畫中調(diào)用這個(gè)方法layoutIfNeeded,在約束后添加[self.view layoutIfNeeded];

蘋果官方文檔對(duì)這兩個(gè)方法的解釋:Allows you to perform layout before the drawing cycle happens. -layoutIfNeeded forces layout early

2.drawRect

這個(gè)方法是用來重繪的。

drawRect在以下情況下會(huì)被調(diào)用:

1>、如果在UIView初始化時(shí)沒有設(shè)置rect大小,將直接導(dǎo)致drawRect不被自動(dòng)調(diào)用。drawRect調(diào)用是在Controller->loadView, Controller->viewDidLoad 兩方法之后掉用的.所以不用擔(dān)心在控制器中,這些View的drawRect就開始畫了.這樣可以在控制器中設(shè)置一些值給View(如果這些View draw的時(shí)候需要用到某些變量值).
2>、該方法在調(diào)用sizeToFit后被調(diào)用,所以可以先調(diào)用sizeToFit計(jì)算出size。然后系統(tǒng)自動(dòng)調(diào)用drawRect:方法。
3>、通過設(shè)置contentMode屬性值為UIViewContentModeRedraw。那么將在每次設(shè)置或更改frame的時(shí)候自動(dòng)調(diào)用drawRect:。
4>、直接調(diào)用setNeedsDisplay,或者setNeedsDisplayInRect:觸發(fā)drawRect:,但是有個(gè)前提條件是rect不能為0。
以上1,2推薦;而3,4不提倡

drawRect方法使用注意點(diǎn):
1、若使用UIView繪圖,只能在drawRect:方法中獲取相應(yīng)的contextRef并繪圖。如果在其他方法中獲取將獲取到一個(gè)invalidate的ref并且不能用于畫圖。drawRect:方法不能手動(dòng)顯示調(diào)用,必須通過調(diào)用setNeedsDisplay 或者 setNeedsDisplayInRect局部重繪,讓系統(tǒng)自動(dòng)調(diào)該方法。
2、若使用calayer繪圖,只能在drawInContext: 中(類似于drawRect)繪制,或者在delegate中的相應(yīng)方法繪制。同樣也是調(diào)用setNeedDisplay等間接調(diào)用以上方法
3、若要實(shí)時(shí)畫圖,不能使用gestureRecognizer,只能使用touchbegan等方法來掉用setNeedsDisplay實(shí)時(shí)刷新屏幕

3.-(void)sizeToFit和-(CGSize)sizeThatFits:(CGSize)size

sizeToFit會(huì)自動(dòng)調(diào)用sizeThatFits方法;
sizeToFit不應(yīng)該在子類中被重寫,應(yīng)該重寫sizeThatFits
sizeThatFits傳入的參數(shù)是當(dāng)前的size,返回一個(gè)適合的size
sizeToFit可以被手動(dòng)直接調(diào)用,sizeToFit和sizeThatFits方法都沒有遞歸,對(duì)subviews也不負(fù)責(zé),只負(fù)責(zé)自己
在開發(fā)中,有些控件無需我們?cè)O(shè)置frame,只需要制定size。這個(gè)時(shí)候,我們可以通過直接調(diào)用sizeToFit使這類控件根據(jù)自身的內(nèi)容,獲取自身的大小,顯示出來。
總結(jié):

  • drawRect是對(duì)receiver的重繪,能獲得context
  • layoutSubviews對(duì)subviews重新布局
  • layoutSubviews方法調(diào)用先于drawRect
  • setNeedsLayout在receiver標(biāo)上一個(gè)需要被重新布局的標(biāo)記,在系統(tǒng)runloop的下一個(gè)周期自動(dòng)調(diào)用layoutSubviews(iphone device的刷新頻率是60hz,也就是(1/60)秒后重繪)
  • layoutIfNeeded方法如其名,UIKit會(huì)判斷該receiver是否需要layout.如需要,無需等runloop的下一個(gè)周期,而是立即馬上更新
  • layoutIfNeeded遍歷的不是superview鏈,應(yīng)該是subviews鏈
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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