使用 Auto Layout 将 View 显示在屏幕上需要的经过三个步骤。
与之相关的方法有如下八个。
updateConstraitsIfNeed
。updateConstraints
。此方法可以手动调用。子类不要重写此方法。layoutIfNeeded
。当view的布局改变时会自动调用。layoutSubViews
。updateConstraintsIfNeeded
。当你使用 Auto Layout 去努力创造你想要的布局时,特别是同时伴随高级使用场景和动画时,放下使用场景,去回想布局过程是怎样工作的,将会带来很大的帮助。
相比使用frame布局,Auto Layout 在 Views 可以被显示之前引入了两个额外的处理工序:更新约束,布局视图
每一步都依赖前一步;显示依赖布局,布局依赖约束。
第一步:更新约束(updateConstraints)
更新约束可以被认为是一个测量的过程。他从下到上 bottom-up (from subview to super view)去准备在布局时直接设置 views 的 frame 所需要的信息。
你可用setNeedsUpdateConstraints
手动触发这个过程。也可以通过对自身约束系统的改变来自动触发这个过程。即便这样,当你在定制 views 中改变可能影响布局的的约束时通知 Auto Layout 也是有必要的。
说到定制的 views,你可以重写updateConstraints
以添加你的 view 在这个阶段需要的局部约束。
第二步:布局(Layout)
布局是从上到下 top-down (from super view to subview)进行的。布局的过程事实上是请求约束系统的结果再通过 center 和 bounds 设置给 views。
你可以通过调用setNeedsLayout
触发这个过程。setNeedsLayout 实际上并没有在接下来立马请求布局,而是把你的请求记录下来随后刷新。
通过这种方法你不用担心setNeedsLayout
调用太频繁,因为所有的布局请求会被合并到一个布局过程。你可以通过调用layoutIfNeeded
来立即触发更新视图层的布局过程,如果你下一步操作依赖于视图最新的布局。
在你的定制 view 中你可以通过重写layoutSubviews
去获取布局过程的完全控制。我们将在随后展示这样的用法。
第三部:显示(Display)
最后,显示过程将 views 渲染到屏幕,这个过程是独立的,不管你用没用 Auto Layout。
显示过程从上到下 top-down (from super view to subview) 进行,可以用 setNeedsDisplay 触发,并且会整合所有请求延时重绘。在你的定制 views 重写熟悉的drawRect:
方法是你获得 views 在显示过程这个阶段的完全控制的途径。
因为每一步都依赖于前一步,所以显示过程将会触发布局过程(如果有任何布局在等待改变)。同样,布局过程将会触发新更新约束过程(如果约束系统有在等到的改变)。
需要记住的是,这三个过程的调用顺序并不是唯一的。
布局(基于约束 Constraint-based 的)是一个重复的过程。在布局过程中基于上一次布局结果改变约束,将会在下一个布局过程后再次触发约束更新。
这将有助于生成 views 高级定制的布局。但是你也有陷入无限循环的风险,如果每个layoutSubviews
方法中调用并唤起了另外一个布局过程的话。
setNeedsUpdateConstraints
后调用updateConstraintsIfNeeded
。setNeedsLayout
后调用layoutIfNeeded
。
setNeedsUpdateConstraints : 当一个自定义的View某一个属性的改变可能影响到界面布局,我们应该调用这个方法来告诉布局系统在未来某个时刻需要更新。系统会调用updateConstraints去更新布局。
updateConstraints :自定义View时,我们应该重写这个方法来设置当前view局部的布局约束。重写这个方法时,一定要调用[super updateConstraints]
。
needsUpdateConstraints :布局系统使用这个返回值来确定是否调用updateConstraints
updateConstraintsIfNeeded :我们可以调用这个方法触发update Constraints的操作。在needsUpdateConstraints返回YES时,才能成功触发update Constraints的操作。我们不应该重写这个方法。
Auto Layout的布局过程是 update constraints(updateConstraints)-> layout Subviews(layoutSubViews)-> display(drawRect) 这三步不是单向的,如果layout的过程中改变了constrait, 就会触发update constraints,进行新的一轮迭代。我们在实际代码中,应该避免在此造成死循环。