美文网首页
Autolayout之修改约束

Autolayout之修改约束

作者: 我才是臭吉吉 | 来源:发表于2019-03-04 16:54 被阅读1次

    注:本文翻译自Changing Constraints

    对一个约束进行所有的改变实质上就是修改该约束的数学表达式(见图17-1)。你可以在Anatomy of a Constraint中查看更多关于约束方程的信息。

    图17-1 约束方程式

    img

    下列所有行为都会改变一个或多个约束:

    • 激活或失效约束
    • 修改约束的常数值(constant value)
    • 修改约束的优先级
    • 从视图层级中移除视图

    其他改变,如设置控件的属性,或是修改视图层级,都可以改变约束。当改变发生时,系统会预设置出一个延迟布局阶段(查看The Deferred Layout Pass)。

    一般来说,你可以在任意时刻设置这些修改。理想情况下,大多数约束都会在Interface Builder中设置,或者是在ViewController的初始化配置时(如viewDidLoad)通过代码创建。如果你需要在运行时动态修改约束,通常最好的方式就是在应用程序状态变化时进行修改。例如,如果你想修改一个约束来响应按钮的点击操作,那就直接在该按钮的动作方法中进行修改。

    有时候,为了优化性能,你可能需要分阶段进行一系列的修改。要了解更多信息,请查看Batching Changes

    延迟布局阶段(The Deferred Layout Pass)

    为了避免直接更新受影响视图的frame,Auto Layout设置了一个稍后执行的布局阶段。此延迟阶段首先更新布局的约束,之后为视图层级中的所有视图计算frame。

    你可以通过调用setNeedsLayoutsetNeedsUpdateConstraints方法设置自己的延迟布局阶段。

    视图层级中的延迟布局阶段通常由两个阶段组成:

    1. 如果需要,在更新阶段(Update Pass)更新约束
    2. 如果需要,在布局阶段(Layout Pass)重设视图的frame
    更新阶段

    系统会遍历视图层级,并在所有的ViewController上调用updateViewConstraints方法、在所有视图上调用updateConstraints方法。你可以覆盖这些方法来优化约束的修改(查看Batching Changes)。

    布局阶段

    系统再一次遍历视图层级,并在所有ViewController上调用viewWillLayoutSubviews、在所有视图上调用layoutSubViews。默认来说,layoutSubViews方法会使用Auto Layout引擎算出的矩形来更新每个子视图的frame。你可以覆盖这些方法来修改布局(查看Custom Layouts)。

    分阶段修改(Batching Changes)

    在有影响的修改发生后,直接更新约束应该总是最简洁、最方便的方式。将这些修改延迟到之后的方法中执行,会使代码更加复杂并难以理解。

    可是,总有一些时候你想要为了优化性能而进行分阶段的修改。如当修改约束的地方执行太慢,或是视图正在进行许多冗余修改时,使用这种方式便可以解决。

    要对改变进行分阶段执行,不要直接进行修改,而是在包含该约束的视图上调用setNeedsUpdateConstraints方法。之后,覆盖视图的updateConstraints方法来修改受影响的约束。

    说明

    你的updateConstraints的实现必须尽可能高效。不要让所有的约束失效(deactivate),可以根据需要失效其中一部分。此外,你的app必须存在某些方式来追踪约束,并且可以在每一个更新阶段来验证它们。只改变那些需要改变的项目。在每一次更新阶段中,你必须确保为app的当前状态提供了适合的约束。

    updateConstraints方法实现中,最后一步一定要调用父类的实现。

    不要在你的updateConstraints方法中调用setNeedsUpdateConstraints方法。调用setNeedsUpdateConstraints会设置另一个更新阶段,进而生成了调用循环。

    自定义布局(Custom Layouts)

    覆盖viewWillLayoutSubViewslayoutSubViews方法来修改layout引擎返回的结果。

    重点

    如果可能,使用约束来定义所有的布局。这可以使布局结果更加健壮且更易调试。当你需要创建一个布局,且此布局仅仅通过约束无法达到要求时,你只能通过覆盖viewWillLayoutSubViewslayoutSubViews方法进行处理。

    在覆盖这些方法时,布局正处在一个不确定的状态。一部分视图可能已经布局完,另一部分则没有。在修改视图层级时,你需要非常小心,否则很可能就会导致调用循环。如下规则可以帮助你避免调用循环:

    • 你必须在方法的某处调用父类的实现。
    • 你可以安全地在子树中让视图布局无效化;可是,你必须在调用父类的实现之前做这件事。
    • 不要让在子树外的任何视图布局无效化。这会导致调用循环。
    • 不要调用setNeedsUpdateConstraints。你刚刚完成了一次更新阶段。调用此方法会产生一个调用循环。
    • 不要调用setNeedsLayout。调用此方法会产生一个调用循环。
    • 修改约束时要格外小心。你不能意外地让子树外的视图布局无效化。

    相关文章

      网友评论

          本文标题:Autolayout之修改约束

          本文链接:https://www.haomeiwen.com/subject/aciiuqtx.html