Auto Layout的生命周期
Auto Layout 不只有布局算法 Cassowary,还包含了布局在运行时的生命周期等一整套布局引擎系统,用来统一管理布局创建、更新和销毁。这套系统叫做Layout Engine
Auto Layout布局流程
关于Auto Layout的布局流程,Apple给出图示如上:即Layout Cycle是一个在App运行循环RunLoop下循环执行的一个过程。
App启动后开启RunLoop,循环检测图层树中是否存在约束变化;
当发生Constrints Change(直接or间接设置、更新、移除约束),RunLoop检测到约束变化;
RunLoop发现约束变化后,就会进入Deferred Layout阶段,视图的位置、尺寸值会在这个过程计算,设置到对应视图上,并绘制出来;
执行完一轮布局,RunLoop会继续检查视图树的约束更新情况,当再次发现约束更新,则执行新一轮布局……
Constraints Change (约束变化)
Constraints Change过程包括两个步骤:约束更新;Layout Engine重新计算布局,获取到布局后调用superview.setNeedLayout()
,然后进入Deferred Layout Pass。
Deferred Layout Pass (延迟布局)
Deferred Layout Pass 分为两步:
- 更新约束:从下往上(子视图到父视图),依次遍历视图层级,调用View的
updateConstraints
方法(或ViewController的updateViewConstraints
方法)来更新约束(你可以在此覆盖本方法来设置自定义约束,且在此设置时,执行效率最高。记得最后调用父类实现)。 - 给视图及子视图重新设定位置(给view的frame赋值):从上到下依次调用View的layoutSubViews方法(或ViewController的viewLayoutSubViews方法),从Layout Engine中取出预算好的frame进行赋值(你可以覆盖此方法实现自定义布局,不过此刻不是稳态,需要在适合时候调用父类实现)。
延迟布局的触发条件
setNeedsUpdateConstraints
下一次loop执行updateConstraints
updateConstraintsIfNeeded
立即执行updateConstraints
setNeedsLayout
下一次loop执行layoutSubViews
layoutIfNeeded
立即执行layoutSubViews
setNeedDisplay
下一次loop执行draw
view的改变会调用哪些方法
- 改变
frame.origin
不会掉用layoutSubviews
- 改变
frame.size
会使superVIew
的layoutSubviews
调用 - 改变
bounds.origin
和bounds.size
都会调用superView
和自己view
的layoutSubviews
方法
参考链接:https://github.com/ming1016/study/wiki/深入剖析Auto-Layout,分析iOS各版本新增特性