取消隐藏后如何保留堆栈视图子项的约束?

Posted

技术标签:

【中文标题】取消隐藏后如何保留堆栈视图子项的约束?【英文标题】:How to retain constraints for a Stack View's child after unhiding? 【发布时间】:2020-06-04 17:10:44 【问题描述】:

有一个堆栈视图,其中包含三个标签并具有以下约束:

高度 = 300 顶部 = 安全区域 + 50 尾随/前导 = 0

以及以下属性:

轴 -> 垂直 对齐 -> 居中 分布 -> 等间距

标签 3(蓝色)有一个变化:对于紧凑型高度尺寸类,已安装属性被禁用(通过属性检查器配置)。这使它隐藏在 iPhone 上的水平方向:

当应用启动时,所有标签在屏幕上都有正确的位置。旋转到水平方向并返回后,Label 3 放置在 Stack View 的左上角,而其他标签正确对齐:

Xcode View Hierarchy 调试器显示标签 3 重新出现后没有任何 UIStackView 相关约束,并且旁边的警告显示“Position is ambiguous”:

标签 3 似乎在被隐藏并再次显示后失去了与 Stack View 相关的所有约束。

【问题讨论】:

为什么要直接在UIStackView 中添加约束?如果有的话,您应该将它们添加到 UIView 内的 UIStackView 内。但这会导致很多问题。你真的应该嵌套UIStackView 目前的约束只是定义堆栈视图本身的位置和高度的约束。据我了解,调试器屏幕截图上可见的约束是由框架动态添加的。我不明白为什么应该有嵌套的堆栈视图,而不是一个具有 3 个子标签的单个视图。 我的错,我以为你出于某种原因手动向所有 UILabel 元素添加约束。 @raindev - 试着澄清你在做什么......你说 “标签 3(蓝色)有一个变化:如果高度特征是紧凑的,它就没有安装,使它隐藏在iPhone 上的水平方向” --- 你设置了什么约束来“让它隐藏”?显示包含所有约束的 Storyboard 布局。 @DonMag,通过 Attributes Inspector 配置的 Compact 高度尺寸类的 Installed 属性有一个变体,更新了问题中的措辞。还添加了故事板屏幕截图。我希望它能把问题弄清楚。 【参考方案1】:

您不能为此使用installed 属性,因为它会向超级视图添加/删除视图。这对于 StackView 来说还不够好,因为它需要使用 addArrangedSubview() 添加子视图。

一个简单的解决方案是为您的标签创建一个出口,并在旋转时隐藏/显示它:

@IBOutlet private var label3: UILabel!

override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) 
    super.willTransition(to: newCollection, with: coordinator)

    label3.isHidden = newCollection.verticalSizeClass == .compact

【讨论】:

感谢 Gereon 的回答!您能否就installed 属性的用途提供一些指导?鉴于它的名称,在网上很难找到有关它的信息,并且在UIView 的文档中也没有提到它。 供以后参考:willTransitionUIContentContainer 的实例方法,UIViewController 实现的与大小/特征更改相关的逻辑协议。 我找不到任何当前文档,但installed 纯粹是一个 IB 概念,而不是 UIView 上的属性。引用此old doc:“仍然会创建已卸载视图的运行时对象。但是,视图和任何相关约束都不会添加到视图层次结构中,并且视图具有 nil 的超级视图属性。这与隐藏不同. 隐藏的视图与任何相关的约束一样位于视图层次结构中。”【参考方案2】:

一种简单得多的方法 - 在 Hidden 属性上设置特征变化。

这是你的布局:

选择底部标签,然后在“属性检查器”窗格中,单击Hidden 旁边的+ 按钮:

将变体更改为:

您现在可以选择一个新的Hidden 变体:

这是您在旋转到 wC hC 时得到的结果:

正如这些图片所示,您甚至可以在 Storyboard 中看到结果...在运行时无需等待代码。

【讨论】:

感谢另一个很好的回答!引用UIStackView 的文档:“每当视图被添加、删除或插入到arrangedSubviews 数组中,或者每当排列的子视图的isHidden 属性之一发生变化时,堆栈视图都会自动更新其布局。”由于子视图从未从arrangedSubviews 中删除,因此在不更新arrangedSubviews 的情况下将其作为UIStackView 的子视图添加回来没有问题。

以上是关于取消隐藏后如何保留堆栈视图子项的约束?的主要内容,如果未能解决你的问题,请参考以下文章

如何快速隐藏和取消隐藏具有高度的视图?

如何在收藏视图中隐藏/取消隐藏部分

如何在滚动视图中隐藏和取消隐藏 UiViews 中的浮动按钮?

当用户快速滚动表格视图时如何隐藏和取消隐藏导航栏?

取消隐藏 UIStackView 元素时的动画方向

UIProgressView 约束问题