一般情况下,Constraints都是在设计阶段就计算完成,如果需要在运行时改变Constraints,最好是在状态发生变化时,例如按钮被点击。
The Deferred Layout Pass
AutoLayout并不会直接改变View的Frames,而是通过Layout Pass的方式来进行更新。Layout Pass更新layout的Constraints,然后计算出所有View的frames来进行更新。
调用以下两个方法之一来进行Layout Pass:
1 | setNeedsLayout |
The Deferred Layout Pass将会在View结构树中传递两个Pass:
Update Pass
Update Pass将会更新Constraints,系统将会在所有ViewController中调用方法:
1 | updateViewConstraints |
并在所有的View中调用方法:
1 | updateConstraints |
如果需要进一步优化性能,可以自定义updateConstraints方法。自定义时,需要注意:
- 不要在updateConstraints方法中调用setNeedsUpdateConstraints方法,否则会发生死锁;
- 调用super方法;
- updateConstraints应该尽可能地高效;
- 不要deactivate所有Constraints,只reactivate需要更新的constraint即可;
- 只改变需要变化的View的Constraints。
Layout Pass
Layout Pass将会更新Frames,系统将会在所有ViewController中调用方法:
1 | viewWillLayoutSubviews |
并在所有的View中调用方法:
1 | layoutSubviews |
如果需要进一步优化性能,可以自定义这两个方法。自定义时,需要注意:
- 不要调用setNeedsUpdateConstraints和setNeedsLayout方法,否则会发生死锁;
- 调用super方法;
- 如果需要invalidate一个View的layout,记得在调用super方法之前,并确认该View是处于SubTree中。