iOS開發自定義View佈局子控制元件

weixin_34120274發表於2016-12-14

iOS開發中,- (void)layoutSubviews{}方法及相關方法注意點!!


文章著重介紹iOS開發中如果給subViews設定fram

layout相關的方法

- (void)layoutSubviews {};
- (void)layoutIfNeeded {};
- (void)setNeedsLayout {};
- (CGSize)sizeThatFits:(CGSize)size {};
- (void)sizeToFit {};
- (void)setNeedsDisplay {};
- (void)drawRect {};

一、-(void)layoutSubviews{}在以下情況下會被呼叫/被觸發??

  • 1、[self setNeedsLayout]
  • 2、addSubview會觸發layoutSubviews
  • 3、設定view的Frame會觸發layoutSubviews,當然前提是frame的值設定前後發生了變化
  • 4、滾動一個UIScrollView會觸發layoutSubviews
  • 5、旋轉Screen會觸發父UIView上的layoutSubviews事件

(在蘋果的官方文件中強調:
You should override this method only if the autoresizing behaviors of the subviews do not offer the behavior you want.layoutSubviews, 當我們在某個類的內部調整子檢視位置時,需要呼叫。反過來的意思就是說:如果你想要在外部設定subviews的位置,就不要重寫。)

1.1.什麼時候,需要重寫- (void)layoutSubviews{}呢??
  • view是系統的,不需要重寫,如果view是自定義的,需要重寫。
  • -layoutSubviews方法:這個方法裡面,預設沒有做任何事情,需要子類進行重寫,自定義view時,手動重寫,這裡面只能寫subview的frame限制。
1.2. 如何手動觸發這個方法(- (void)layoutSubviews{})?

iOS開發中,開發者不能直接呼叫這個方法,系統預設不允許我們這樣,那怎麼在需要的時候,手動觸發這個方法呢?下面提供兩個方法。。

  • -(void)setNeedsLayout {};//作用:告之view,需要重新佈局,在未來某個時間點系統非同步觸釋出局方法,且標記view.subViews需要重新佈局。這個方法使用後,view不會立即重新整理,但layoutSubviews{}一定會被呼叫.
  • -(void)layoutIfNeeded {};//如果:有需要重新整理的標記,立即呼叫layoutSubviews進行佈局(如果沒有標記,不會呼叫layoutSubviews)
  • 開發中示例:
    • 1.需要立即重新整理view的frame
       [self layoutIfNeeded];//更改最新的標記
      
    • 2.在初始化方法init這類方法裡、或view第一次顯示之前,系統預設標記“需要重新整理”,故此:這些地方我們可直接呼叫-(void)layoutIfNeeded{} eg:[view layoutIfNeeded]
    • 3.需要多次修改佈局,修改完每處佈局後,還需要下次修改來完善佈局,那這次佈局就需要做一下標記
      //假設需要4出更改佈局
       - (void)change_01~03//1-3處更改,用setNeedsLayout標記
       {  
           [self setNeedsLayout];//更改最新的標記
       }
       - (void)change_04//等到所有佈局晚上後
       {  
           [self layoutIfNeeded];//更改最新的標記
       }
      

二、重繪製相關方法

開發者:重新繪製一個嶄新的view,需要重寫-(void)drawRect:(CGRect)rect {}

1.1.什麼時候,需要重寫-(void)drawRect:(CGRect)rect {}呢??
  • 取決開發者的個人愛好。
1.2. 如何手動觸發這個方法(- (void) drawRect:(CGRect)rect{})?

iOS開發中,開發者不能直接呼叫這個方法,系統預設不允許我們這樣,那怎麼在需要的時候,手動觸發這個方法呢?下面提供兩個方法。。

  • -(void) setNeedsDisplay {};//作用:標記為需要重繪,非同步呼叫drawRect.
  • -(void) setNeedsDisplayInRect:(CGRect)invalidRect {};//標記為需要區域性重繪.

三、其他與佈局subViews.frame相關方法

- (CGSize)sizeThatFits:(CGSize)size {};
- (void)sizeToFit {};

注意點:1.無論什麼時候呼叫sizeToFit,其底層實質sizeToFit自動呼叫sizeThatFits方法。2. -(void)sizeToFit {}不應該在子類中被重寫,應該重寫 -(CGSize)sizeThatFits:(CGSize)size {},

  • -(CGSize)sizeThatFits:(CGSize)size {}//返回值為開發者給定的size,引數size:是現在view現有的size。//開發者可自定義控制元件實質返回的大小。
3.1.sizeToFit的用途?
  • 在開發中,經常用到UIButton,UIBarButtonItem,UITableView的組頭,組尾,表頭,表尾.類似控制元件。他們無需我們設定frame,只需要制定size。這個時候,我們可以通過直接呼叫sizeToFit是這類控制元件根據自身的內容,獲取自身的大小,顯示出來。
3.2. sizeThatFits的用途?
  • 在實際開發中這個方法一般沒有什麼用途,因為它不需要我們手動呼叫。其次:我們都很相信蘋果,會給我們返回合理的size。
  • 除非:自定義view,重寫它,限制自身view的大小。方便外層呼叫sizeToFit時,view顯示的大小是固定的(you給定的size)
3.3.注意:
  • sizeToFit和sizeThatFits方法都沒有遞迴,對subviews也不負責,只負責自己

補充:

  • drawRect是對receiver的重繪,能獲得context
  • layoutSubviews對subviews重新佈局
  • layoutSubviews方法呼叫先於drawRect

  • setNeedsLayout在receiver標上一個需要被重新佈局的標記,在系統runloop的下一個週期自動呼叫layoutSubviews(iphone device的重新整理頻率是60hz,也就是(1/60)秒後重繪)
  • layoutIfNeeded方法如其名,UIKit會判斷該receiver是否需要layout.如需要,無需等runloop的下一個週期,而是立即馬上更新
  • layoutIfNeeded遍歷的不是superview鏈,應該是subviews鏈

後期會更新自動佈局相關方法-(void)updateConstraints

- (void)updateConstraints{}
- (BOOL)needsUpdateConstraints{}
- (void)setNeedsUpdateConstraints{}

相關文章