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 的方法

相关文章
相关标签/搜索