iOS layoutSubviews 和 layoutIfNeeded

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

  • init初始化不會觸發(fā)layoutSubviews
    但是是用initWithFrame 進(jìn)行初始化時(shí),當(dāng)rect的值不為CGRectZero時(shí),會觸發(fā)
  • addSubview會觸發(fā)layoutSubviews
  • 設(shè)置view的Frame會觸發(fā)layoutSubviews,當(dāng)然前提是frame的值設(shè)置前后發(fā)生了變化
  • 滑動(dòng)UIScrollView的時(shí)候。
  • 旋轉(zhuǎn)Screen會觸發(fā)父UIView上的layoutSubviews事件(這個(gè)我驗(yàn)證了一下 確實(shí)沒有觸發(fā)layoutSubviews方法,查了很多資料都說會觸發(fā),大家自己定奪)。

layoutSubviews 方法只能被系統(tǒng)觸發(fā)調(diào)用,程序員不能手動(dòng)直接調(diào)用該方法。要引起該方法的調(diào)用,可以調(diào)用 UIView 的setNeedsLayout方法來標(biāo)記一個(gè) UIView。這樣一來,在 UI 線程的下次繪制循環(huán)中,系統(tǒng)便會調(diào)用該 UIView 的 layoutSubviews 方法。

layoutIfNeeded

也就是使用約束的時(shí)候 調(diào)一下可以立即更新效果
setNeedsLayout方法并不會立即刷新,立即刷新需要調(diào)用layoutIfNeeded方法!

setNeedsDisplay

與setNeedsLayout方法相似的方法是setNeedsDisplay方法。該方法在調(diào)用時(shí),會自動(dòng)調(diào)用drawRect方法。drawRect方法主要用來畫圖。所以,當(dāng)需要刷新布局時(shí),用setNeedsLayOut方法;當(dāng)需要重新繪畫時(shí),調(diào)用setNeedsDisplay方法。


看看官方解釋:

setNeedsLayout :

Call this method on your application’s main thread when you want to adjust the layout of a view’s subviews. 
This method makes a note of the request and returns immediately. 
Because this method does not force an immediate update, but instead waits for the next update cycle, 
you can use it to invalidate the layout of multiple views before any of those views are updated. 
This behavior allows you to consolidate all of your layout updates to one update cycle, which is usually better for performance.

如果要調(diào)整視圖子視圖的布局,請?jiān)趹?yīng)用程序的主線程上調(diào)用此方法。
此方法記錄請求并立即返回。
因?yàn)榇朔椒ú粡?qiáng)制立即更新,而是等待下一個(gè)更新周期 
所以可以使用它在更新任何視圖之前使多個(gè)視圖的布局無效
此行為允許您將所有布局更新合并到一個(gè)更新周期,這通常會提高性能。

layoutIfNeeded:

Use this method to force the view to update its layout immediately. 
When using Auto Layout, the layout engine updates the position of views as needed to satisfy changes in constraints. 
Using the view that receives the message as the root view, this method lays out the view subtree starting at the root. 
If no layout updates are pending, this method exits without modifying the layout or calling any layout-related callbacks.

使用此方法可強(qiáng)制視圖立即更新其布局
使用“自動(dòng)布局”時(shí),布局引擎會根據(jù)需要更新視圖的位置,以滿足約束的更改
使用接收消息的視圖作為根視圖,此方法從根開始布置視圖子樹
如果沒有布局更新掛起,則此方法將退出,而不修改布局或調(diào)用任何與布局相關(guān)的回調(diào)
結(jié)論:

setNeedsLayout : 方法記錄更新請求并立即返回; 不強(qiáng)制立即更新,而是等待下一個(gè)更新周期;
應(yīng)用場景:適用于所有布局更新合并到一個(gè)更新周期,這通常會提高性能;

layoutIfNeeded可強(qiáng)制視圖立即更新其布局,使用“自動(dòng)布局”時(shí),布局引擎會根據(jù)需要更新視圖的位置,以滿足約束的更改;但會以接收消息的視圖作為根視圖,從根視圖開始布局視圖樹;

區(qū)別:
  • 觸發(fā)layoutSubviews的時(shí)機(jī)不同,前者會在runloop 即將休眠時(shí)觸發(fā),且一定會觸發(fā);后者會立即觸發(fā),但前提是控件的布局發(fā)生了改變,如果沒改變就不會觸發(fā)
    這里的改變:是指用frame布局 width、 height; x、y軸的值改變無效果

  • Masonry 只要修改布局就會觸發(fā)layoutSubviews,不修改不會


setNeedsDisplay

Marks the receiver’s entire bounds rectangle as needing to be redrawn.

You can use this method or the setNeedsDisplayInRect: to notify the system that your view’s contents need to be redrawn. This method makes a note of the request and returns immediately. The view is not actually redrawn until the next drawing cycle, at which point all invalidated views are updated.

可以使用此方法或setNeedsDisplayInRect:通知系統(tǒng)需要重新繪制視圖的內(nèi)容。
此方法記錄請求并立即返回。
在下一個(gè)繪圖周期之前,視圖實(shí)際上不會重新繪制,此時(shí)所有無效的視圖都會更新。

You should use this method to request that a view be redrawn only when the content or appearance of the view change.
 If you simply change the geometry of the view, the view is typically not redrawn. 
Instead, its existing content is adjusted based on the value in the view’s contentMode property.
Redisplaying the existing content improves performance by avoiding the need to redraw content that has not changed.

注意

如果視圖由caeAglayer對象支持,則此方法無效。它僅適用于使用本機(jī)繪圖技術(shù)(如UIKit和核心圖形)渲染其內(nèi)容的視圖。

應(yīng)該使用此方法請求僅當(dāng)視圖的內(nèi)容或外觀更改時(shí)才重新繪制視圖。如果僅更改視圖的幾何圖形,則通常不會重新繪制視圖。而是根據(jù)視圖的contentMode屬性中的值調(diào)整其現(xiàn)有內(nèi)容。重新顯示現(xiàn)有內(nèi)容可以避免重新繪制未更改的內(nèi)容,從而提高性能。

名詞解釋:CAEAGLayer (用OpenGL ES繪制的層)
結(jié)論:

記錄請求并立即返回,在下一個(gè)繪圖周期之前,視圖實(shí)際上不會重新繪制;
使用此方法請求僅當(dāng)視圖的內(nèi)容或外觀更改時(shí)才重新繪制視圖, 僅更改視圖幾何圖形不回重繪;
應(yīng)用場景:僅適用于使用本機(jī)繪圖技術(shù)(如UIKit和核心圖形)渲染其內(nèi)容的視圖


layoutSubviews的解釋:

The default implementation of this method does nothing on iOS 5.1 and earlier. Otherwise, the default implementation uses any constraints you have set to determine the size and position of any subviews.
Subclasses can override this method as needed to perform more precise layout of their subviews. You should override this method only if the autoresizing and constraint-based behaviors of the subviews do not offer the behavior you want. You can use your implementation to set the frame rectangles of your subviews directly.
You should not call this method directly. If you want to force a layout update, call the setNeedsLayout method instead to do so prior to the next drawing update. If you want to update the layout of your views immediately, call the layoutIfNeeded method.

此方法的默認(rèn)實(shí)現(xiàn)在iOS5.1及更早版本上不起任何作用。否則,默認(rèn)實(shí)現(xiàn)將使用您設(shè)置的任何約束來確定任何子視圖的大小和位置。

子類可以根據(jù)需要重寫此方法,以便對其子視圖執(zhí)行更精確的布局。僅當(dāng)子視圖的自動(dòng)調(diào)整大小和基于約束的行為不提供所需的行為時(shí),才應(yīng)重寫此方法??梢允褂脤?shí)現(xiàn)直接設(shè)置子視圖的框架矩形。

不應(yīng)直接調(diào)用此方法。如果要強(qiáng)制布局更新,請?jiān)谙麓螆D形更新之前調(diào)用setNeedsLayout方法。如果要立即更新視圖的布局,請調(diào)用layoutIfNeeded方法。


UIView的setNeedsDisplay(需要重新顯示,繪制)和setNeedsLayout(需要 重新布局)方法。首先兩個(gè)方法都是異步執(zhí)行的。而setNeedsDisplay會調(diào) 用自動(dòng)調(diào)用drawRect方法,這樣可以拿到UIGraphicsGetCurrentContext, 就可以畫畫了。而setNeedsLayout會默認(rèn)調(diào)用layoutSubViews,就可以處 理子視圖中的一些數(shù)據(jù)。


參考:iOS layoutSubviews 和 layoutIfNeeded
iOS setNeedsLayout、layoutIfNeeded、setNeedsDisplay

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

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

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