UIStackView 在旋转时隐藏视图和不满意的布局

UIStackView hiding views and unsatisfiable layout on rotation

我有一个视图控制器,我想在其中隐藏某些子视图、标签等,具体取决于特征集合是什么。例如,我在水平压缩时要隐藏的侧面有标签,垂直压缩时我想隐藏顶部和底部的标签。

因为我想隐藏界面的整个部分,听起来 UIStackView 会让这更容易。同样,我正在尝试在 Interface Builder / Xcode (9.1 9B55) 中做尽可能多的事情,而不是在代码中,尽量保持简单。

设计的主要元素是棋盘,其中:

然后它周围的标签和其他项目我想根据当前特征集合移动和隐藏。

我已经开始构建一个水平堆栈视图、对齐方式和分布设置为 "Fill." 其中有两个项目,boardView(紫色)和 labelView(黄色)。

labelView 中有几个标签,在视图本身内为这些标签的布局设置了约束。

boardView 有纵横比约束 1:1 (@1000):

我为堆栈视图设置了以下约束,将其固定到超级视图(底部除外):

我设置了这些约束以确保 boardView 永远不会溢出 superview:

然后我将这些约束设置为较低的优先级,这样,如果可能的话,宽度或高度将扩展以填充超级视图(但不会溢出,因为它们的优先级低于上面):

这一切似乎都很有效。 Xcode 内没有错误,应用程序的行为符合我的预期,纵向和横向(这些屏幕截图来自 iPhone 8 模拟器):

当我试图隐藏右视图时,问题就来了。当我们垂直处于常规模式时,我试图通过隐藏 nameView 来做到这一点。我 select nameView,单击 Installed 复选框旁边的 +,select hR:

然后取消选中 hR 的“已安装”框:

这在 Xcode 中看起来很棒。没有错误,IB 似乎显示了我所期望的横向和纵向(名称标签被隐藏的地方)的所有视图:

到目前为止,还不错。事实上,当我 运行 它时,它看起来就像我们最初期望的那样。如果我们在景观中启动模拟器,它看起来不错:

如果我们以纵向启动模拟器,它看起来不错:

所以问题是什么?好吧,一旦我们从纵向旋转到横向,布局就完全错误了:

同时,我们在控制台中得到一个 LayoutConstraints 错误:

2017-12-03 19:25:55.710381-0600 TestLayoutSIngleView[31439:3231004] [LayoutConstraints] 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 fixes it. 
(
    "<NSLayoutConstraint:0x60400009b8a0 UIView:0x7fe920603e90.width == UIView:0x7fe920603e90.height   (active)>",
    "<NSLayoutConstraint:0x60000009ced0 UIStackView:0x7fe92050bd70.leading == UILayoutGuide:0x6000001b5d20'UIViewSafeAreaLayoutGuide'.leading   (active)>",
    "<NSLayoutConstraint:0x60000009d100 UIStackView:0x7fe92050bd70.top == UILayoutGuide:0x6000001b5d20'UIViewSafeAreaLayoutGuide'.top   (active)>",
    "<NSLayoutConstraint:0x60000009d150 UILayoutGuide:0x6000001b5d20'UIViewSafeAreaLayoutGuide'.trailing == UIStackView:0x7fe92050bd70.trailing   (active)>",
    "<NSLayoutConstraint:0x60000009d1a0 UILayoutGuide:0x6000001b5d20'UIViewSafeAreaLayoutGuide'.bottom >= UIStackView:0x7fe92050bd70.bottom   (active)>",
    "<NSLayoutConstraint:0x60000009e5a0 'UISV-canvas-connection' UIStackView:0x7fe92050bd70.leading == UIView:0x7fe920603e90.leading   (active)>",
    "<NSLayoutConstraint:0x60000009ce30 'UISV-canvas-connection' UIStackView:0x7fe92050bd70.top == UIView:0x7fe920603e90.top   (active)>",
    "<NSLayoutConstraint:0x60000009e5f0 'UISV-canvas-connection' V:[UIView:0x7fe920603e90]-(0)-|   (active, names: '|':UIStackView:0x7fe92050bd70 )>",
    "<NSLayoutConstraint:0x60000009cde0 'UISV-canvas-connection' H:[UIView:0x7fe920603e90]-(0)-|   (active, names: '|':UIStackView:0x7fe92050bd70 )>",
    "<NSLayoutConstraint:0x60000009e7d0 'UIView-Encapsulated-Layout-Height' UIView:0x7fe92050b8f0.height == 375   (active)>",
    "<NSLayoutConstraint:0x60000009e780 'UIView-Encapsulated-Layout-Width' UIView:0x7fe92050b8f0.width == 667   (active)>",
    "<NSLayoutConstraint:0x60000009d060 'UIViewSafeAreaLayoutGuide-bottom' V:[UILayoutGuide:0x6000001b5d20'UIViewSafeAreaLayoutGuide']-(0)-|   (active, names: '|':UIView:0x7fe92050b8f0 )>",
    "<NSLayoutConstraint:0x60000009d010 'UIViewSafeAreaLayoutGuide-left' H:|-(0)-[UILayoutGuide:0x6000001b5d20'UIViewSafeAreaLayoutGuide'](LTR)   (active, names: '|':UIView:0x7fe92050b8f0 )>",
    "<NSLayoutConstraint:0x60000009d0b0 'UIViewSafeAreaLayoutGuide-right' H:[UILayoutGuide:0x6000001b5d20'UIViewSafeAreaLayoutGuide']-(0)-|(LTR)   (active, names: '|':UIView:0x7fe92050b8f0 )>",
    "<NSLayoutConstraint:0x60000009cfc0 'UIViewSafeAreaLayoutGuide-top' V:|-(0)-[UILayoutGuide:0x6000001b5d20'UIViewSafeAreaLayoutGuide']   (active, names: '|':UIView:0x7fe92050b8f0 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x60400009b8a0 UIView:0x7fe920603e90.width == UIView:0x7fe920603e90.height   (active)>

我喜欢使用 UIStackView 让自动布局和隐藏视图更容易的想法。但是,如果我在 Xcode 中看到的内容在编译时不起作用并且 运行,那么这似乎很棘手。

我做错了什么(或者我 运行 遇到了 Xcode 错误)?

我创建了一个 GitHub 项目来演示以上内容: https://github.com/johnstewart/TestLayoutSIngleView

编辑...当我写完以上所有内容时我突然想到,如果我们要在横向模式下隐藏此视图,布局将无法满足...但我'我没有将此视图隐藏在风景中,仅隐藏在肖像中。出于某种原因,iOS 在旋转之前对布局进行了更改。

如果我将它的优先级设置为 1000 到 750:

...我在控制台上没有收到任何自动布局错误。但是,旋转后的横向视图根本没有正确的位置。

就好像堆栈视图在开始从纵向旋转到横向时立即是 sh运行k,并在旋转完成后将堆栈视图留在那个 sh运行ken 状态,即使现在有足够的空间:

我真诚地希望我在这里遗漏了一些明显的东西...否则我看不出使用 UIStackView 卸载基于特征集合的视图是如何可行的;这似乎是一个简单的示例(确实如此;我还有很多东西要添加!)

编辑:

我看到此技术的 WWDC 视频来自 WWDC2017,Interface Builder 中的自动布局技术 (https://developer.apple.com/videos/play/wwdc2017/412/)。此演示从 29:00.

开始

但是,我错了,是 "Installed" 属性 被用于此目的。正如接受的答案所表明的那样,"Hidden" 是做到这一点的方法。

我觉得不用'installed'属性也能达到你想要的效果: 只需为纵向模式设置 'hidden':