ScrollView 自动布局约束打破设备旋转

Posted

技术标签:

【中文标题】ScrollView 自动布局约束打破设备旋转【英文标题】:UIScrolView auto layout contraints breaking on device rotation 【发布时间】:2014-09-03 12:24:01 【问题描述】:

UIScrollView 及其子视图上设置自动布局约束时,我遇到了一个相当烦人的问题。当设备方向改变时,它会通过以下警告打破约束:

Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this: (1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x7a1b1830 V:[UIView:0x7a1b0520(768)]>",
    "<NSLayoutConstraint:0x7a1c5990 V:[UIView:0x7a1bcf50(1024)]>",
    "<NSLayoutConstraint:0x7a17aa70 V:|-(0)-[UIView:0x7a1b0520]   (Names: '|':UIScrollView:0x7a176520 )>",
    "<NSLayoutConstraint:0x7a1c49c0 V:[UIView:0x7a1b0520]-(0)-|   (Names: '|':UIScrollView:0x7a176520 )>",
    "<NSLayoutConstraint:0x7a172620 V:[UIView:0x7a1bcf50]-(0)-|   (Names: '|':UIScrollView:0x7a176520 )>",
    "<NSLayoutConstraint:0x7a172650 V:|-(0)-[UIView:0x7a1bcf50]   (Names: '|':UIScrollView:0x7a176520 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7a1c5990 V:[UIView:0x7a1bcf50(1024)]>

我在故事板中设置了一个滚动视图,它包含两个容器作为子视图。滚动视图本身固定在超级视图的所有四个侧面(编辑器/引脚/前导-、尾随-、顶部-、底部-空间到超级视图)。这两个容器的边缘通过 Auto-Layout 约束固定到滚动视图,但两者的宽度和高度在情节提要上设置为固定,请参阅 att。图片:

两个容器的宽度和高度通过代码更新,最初是在viewDidLoad() 中,每当设备方向改变时,在didRotateFromInterfaceOrientation() 中:

    _primaryWidth.constant = view.bounds.size.width
    _primaryHeight.constant = view.bounds.size.height
    _secondaryWidth.constant = _primaryWidth.constant - 200
    _secondaryHeight.constant = _primaryHeight.constant

这是出现上述警告并且约束中断并且布局过度的时候。有人能告诉我为什么会发生这种情况以及如何解决吗?

(注意负 200。这是因为正确的容器应该有更小的宽度。但这不会影响问题。即使没有这个,约束也会中断。)

【问题讨论】:

不需要像自动布局那样改变高度和宽度。此外,警告是当您应用过多的自动布局时,您需要更好地阅读自动布局并尝试使用简单的示例来理解它。 如果我在设备旋转后不更新两个容器的宽度/高度,它们将不会将它们的大小更新到屏幕 w/h,这会导致它们垂直滚动并具有错误的大小。 所以自动布局是为了控制调整你的布局。您应该以编程方式而不是 IB 进行自动布局。 @walle84 我对这个逻辑的问题是,如果像这样简单的事情不能用 IB 完全完成,那么 IB 有什么用?!幸运的是,我现在通过 IB 让它工作了。 以编程方式以防万一我们有复杂的视图,那么在这种情况下,IB 就没那么有用了。同样,就像我们有时以编程方式而不是从 IB 获取 uibutton 的原因一样。所以一切都取决于流动。也很好,它可以正常工作,并且 DBD 提供的答案很好!!!! 【参考方案1】:

您有将滚动视图的边缘固定到屏幕边缘的约束,这适用于纵向和横向。您还有一个约束,将您的一个视图的高度设置为 1024。

在纵向中一切正常,但是当您旋转到横向时,您不能将高度为 1024 的东西固定在顶部和底部的屏幕边缘,因为屏幕的高度仅为 768。一个必须去,你可以看到哪个得到斧头。

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7a1c5990 V:[UIView:0x7a1bcf50(1024)]>

删除高度限制,你会没事的。为什么你仍然需要它们?无论您给定的大小如何,您都希望视图固定到屏幕/超级视图的边缘。非任意值还允许您将相同的代码/布局携带到其他设备或作为子视图而无需更改布局。

【讨论】:

感谢@DBD 的提示,但是我在情节提要中没有设置任何限制,设置为 1024 高度。容器视图约束的高度唯一更新的地方是在上面的代码中的 didRotateFromInterfaceOrientation() 中。这是必要的,因为否则容器视图的高度与屏幕高度不同。 哇!自动布局到底有多令人困惑?!以为我几乎想通了。在滚动视图中添加了两个容器的宽度约束,然后应用“添加缺少的约束”这几乎是正确的,即使在旋转到横向时也是如此。但是随后旋转回 Portrait 并且第二个容器视图的宽度和高度没有更新。在这个问题上浪费的时间:3.45 小时。 想通了!奇怪的是,从另一个相关类中的错误视图中获取的宽度导致高度混乱。

以上是关于ScrollView 自动布局约束打破设备旋转的主要内容,如果未能解决你的问题,请参考以下文章

自动布局约束警告“将尝试通过打破约束来恢复”

自动布局和设备旋转中到顶部的比例距离

UICollectionView 自动布局约束正在打破

如何在 ScrollView 中为 ImageView 设置自动布局约束?

横向和纵向模式的自动布局不同的约束

自动布局约束错误