iOS 佈局:layoutSubviews與它的家人們

在一個 Runloop 處理完事件後,最後進入 Update cycle:oop

  1. 更新約束
  2. 佈局:引擎計算視圖和子視圖的 frame 並佈局
  3. 顯示:重繪視圖

Step1:更新約束

updateConstraints()

相似於 layoutSubviews 的機制。佈局

只應該在此方法中實現必需要更新的約束,靜態的約束應在interface builder、視圖的初始化方法或 viewDidLoad() 方法中指定。ui

不該直接調用,應調用觸發方法讓系統處理事件

自動標記約束髮生變化,在下一個週期會觸發 updateConstraints 的行爲:class

  • 設置/解除約束
  • 更改約束優先級
  • 從視圖層級 (view hierarchy) 中移除視圖

setNeedUpdateConstraints()

相似於 setNeedsLayout 的機制,手動標記發生變化,下週期調用 updateConstraints 更新date

updateConstraintsIfNeeded()

相似於 layoutIfNeeded 的機制,檢查視圖的約束是否被標記發生變化,若有變化當即調用 updateConstraints方法

invalidateIntrinsicContentSize()

設置一個標記表示這個視圖的 intrinsicContentSize 已通過期,須要在下一個佈局階段從新計算。layout

視圖的 intrinsicContentSize:視圖根據本身內容獲得的天然尺寸,一般由包含元素的約束約定,也能夠自定義di

Step2:佈局視圖

layoutSubviews()

處理對視圖及其全部子視圖的從新定位和大小調整 會調用子視圖的 layoutSubviews,開銷很大view

不該直接調用,應調用觸發方法讓系統處理

自動標記視圖的佈局發生變化,在下一個週期會觸發 layoutSubviews 的行爲:

  • 經過 setFrame 改變視圖的 bounds(不只是位置)
  • add subview
  • UIScrollView 的滾動(layoutSubviews 會在 UIScrollView 和它的父 view 上被調用)
  • 旋轉設備:調用當前 controller 的 self.view 的 layoutSubviews
  • 更新視圖的 constraints

setNeedsLayout()

手動標記該視圖的佈局發生變化,在下一個週期調用 layoutSubviews 更新

layoutIfNeeded()

檢查視圖的佈局是否被標記發生變化,若有變化當即調用 layoutSubviews

Step3:繪製

drawRect()

相似於 layoutSubviews 的機制,但不會觸發對子視圖方法的調用

不該直接調用,應調用觸發方法讓系統處理

自動標記視圖顯示發生變化,在下一個週期會觸發 drawRect 的行爲:

  • 改變視圖的 bounds

setNeedsDisplayInRect()

相似於 setNeedsLayout 的機制,手動標記發生變化,下週期調用 drawRect 更新

顯示方法沒有相似 layoutIfNeeded 的方法

相關文章
相關標籤/搜索