UIView Auto Layout life cycle

UIView Auto Layout life cycle


Steps overview

  • 當開啟autolayout的UIView,都會經歷下列生命週期。
    • init, update, layout, render。
    • 不絕對是單一方向,任何step都可以觸發先前的step,甚至可以強制重新整個life cycle。

Update step

  • 系統會由上而下去呼叫每個subview的updateConstraints()
  • 基本上,這個step是自動被執行的,但有時候會希望可以手動觸發這個step。
    • 例如,當使用者改變app某個狀態時,會希望畫面產生變化,這時候就要手動觸發這個step。
  • 手動觸發的做法
    • setNeedsUpdateConstraints,會讓目前constraints無效,然後在下一個cycle更新constraints。
    • updateConstraintsIfNeeded,會觸發updateConstraints()這個method。
  [cell.contentView setNeedsUpdateConstraints];
  [cell.contentView updateConstraints];

Layout step

  • 系統會由下而上去呼叫superview的layoutSubviews
  • layoutSubviews是整個life cycle中最常見到被overridden的方法。
    • 當constraints無法滿足去呈現一個畫面時。
    • 手動計算frames。
  • 基本上,layoutSubviews也可以手動被觸發。

    • setNeedsLayout,會讓目前view’s layout無效,然後在下一個cycle更新layout。
    • layoutIfNeeded,會觸發layoutSubviews()這個method。
     [self setNeedsLayout];
     [self layoutIfNeeded];
    
  • 在overridden layoutSubviews時,需要特別注意下列事項。
    • 別忘記執行super.layoutSubviews()。
    • 千萬別呼叫setNeedsLayout,setNeedsUpdateConstraints,不然會造成無限迴圈。
    • 目前這個view所在hierarchy以外的其他view,不要去改動其constraints。
    • 如果要改動這個view所在hierarchy的其他view(parent or child),千萬要小心,有可能觸發其他view的update,而導致無限迴圈。

Rendering

  • UIView會將目前需要呈現pixel的工作交給CALayer進行處理。
  • Rendering step是獨立,不管是否有開啟auto layout。
  • 除非你是在進行一些客製化的繪製OpenGL ES, Core Graphics or UIKit drawing,不然通常不會去overridden drawRect

What about UIViewControllers

  • 在vc的生命週期中,也有相對應的method,讓vc知道目前畫面在constraint update或view Layout是否已經完成。
    • Update phase: updateViewConstraints
    • Layout phase: viewWillLayoutSubviews / viewDidLayoutSubviews
  • 其中viewDidLayoutSubviews是最重要,也最常被overridden。
    • 通知vc目前所有view已經完成layout step了。
    • 這也是最好時機,進行畫面的最後更新,例如改顏色,改frame等。
    • 過了viewDidLayoutSubviews,最後的畫面就會呈現給使用者。

Intrinsic Content Size

  • 透過overridden intrinsicContentSize,來回傳適合目前content的view大小。
- (CGSize)intrinsicContentSize
{
    CGSize size = [super intrinsicContentSize];
    size.width  += self.edgeInsets.left + self.edgeInsets.right;
    size.height += self.edgeInsets.top + self.edgeInsets.bottom;
    return size;
}
  • If a view has an intrinsic size only for one dimension, you should still override intrinsicContentSize and return UIViewNoIntrinsicMetric for the unknown dimension

Alignment Rectangle

  • alignmentRect(forFrame:), frame(forAlignmentRect:) 实现这些方法来重写视图与其他视图的对齐方式。

  • 同樣要將兩個圓形帶有陰影的image進行置中,會發現左邊沒辦法置中。
    • 因為左邊的image的陰影是放在image裡面,而右邊的image的陰影是另外用程式來產生的。

  • The key to understanding their positioning is the difference in alignment rectangles. Since shadow is a part of the left view’s image, it is also a part of its alignment rectangle. Thus, the center of alignment rectangle does not match with the circle center.

results matching ""

    No results matching ""