對於 iOS 中的視圖佈局,正確的使用上面的三個方法是很是重要的,下面就來深刻的講解一下三個方法的做用以及不一樣之處。ios
在開始以前先解釋一個詞:更新週期(update cycle)。swift
所謂的更新週期,即更新當前屏幕視圖的一個過程,它會在當前 run loop 結束時開始。bash
調用該方法:即告訴 App 在更新週期時,佈局和重繪當前視圖及其子視圖。異步
該方法是異步
操做且必須在主線程中調用,它調用完成會當即返回。由於你不知道更新週期何時會開始,因此,調用該方法不能精準的控制視圖約束更新的時間。可是因爲該方法能夠將多個佈局更新在一個更新週期中更新,所以它的性能會更好。oop
調用該方法:即告訴 App 當即
佈局和重繪當前視圖及其子視圖,不須要等待更新週期。佈局
該方法是同步
操做,佈局更新和視圖重繪已在該方法調用完成以前所有更新。post
該方法會根據你設置的約束來肯定子視圖的位置和尺寸。性能
當子視圖執行更加精細的佈局時,能夠重寫該方法。只有當子視圖的自動調整(autoresizing)和基於約束的行爲不能提供所需的行爲時,才應該重寫此方法。動畫
不要直接調用該方法,若是你想強制更新佈局,能夠調用 setNeedsLayout()
方法,若是想馬上更新佈局,能夠調用 layoutIfNeeded()
方法。ui
// 1. 在delegate 方法中調用 layoutIfNeeded() 方法
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 1.1 cell 的具體配置
xxxxx
// 1.2 調用 layoutIfNeeded()
cell.layoutIfNeeded()
return cell
}
// 2. 改變相應約束
xxConstraints.const = 100
// 3. 全文/收起 按鈕的點擊事件 reload 相應 cell
@objc private buttonAction() {
tableView.reloadRows(at: [xxIndexPath], with: .automatic)
}
複製代碼
Apple Document: It is almost always cleaner and easier to update a constraint immediately after the affecting change has occurred. Deferring these changes to a later method makes the code more complex and harder to understand.
Apple 文檔推薦咱們在發生約束改變的狀況時,當即修改約束是最簡單明瞭的方式。好比在按鈕點擊事件中須要更新約束時的代碼:
@IBAction func buttonAction(_ sender: UIButton) {
animationChange()
}
private func animationChange() {
// 在須要改變時,首先改變約束
heightConstraint.constant = 300
//在根據需求處理響應邏輯
UIView.animate(withDuration: 2.0) {
self.view.layoutIfNeeded()
}
}
複製代碼