iOS:具有隐藏视图的布局约束

Posted

技术标签:

【中文标题】iOS:具有隐藏视图的布局约束【英文标题】:iOS: layout constraint with hidden views 【发布时间】:2018-01-30 00:30:23 【问题描述】:

假设我有两个与底部对齐的视图:

V:[Label1]-10-[Label2]-20-|

Label1Label2 之间有 10 点间距,Label2 和底部之间有 20 点间距。

现在,在某些情况下,我需要隐藏Label2,在这种情况下,我想要:

V:[Label1]-15-|

也就是说,Label2 被隐藏,Label1 与底部有 15 个点间距。

我正在情节提要中进行设置,我正在考虑使 15 点间距具有较低的优先级并根据需要隐藏 Label2,但它似乎不起作用。

实现这一目标的最佳方法是什么?

谢谢!

【问题讨论】:

我通常采用的方法是为每个状态创建 2 组约束。然后在隐藏视图时,您可以切换每个约束的活动标志。这对你有用吗? @andrehungaro 是的,这可行,我更倾向于一种需要最少编码的方式(即故事板完成所有工作)。 我明白了。由于隐藏视图不会影响它们的约束,恐怕故事板不会为我们提供那种条件行为。 【参考方案1】:

通过保持您提到的低优先级约束,我找到的更短的解决方案是:

@IBOutlet weak var view2: UIView!
var constraints: [NSLayoutConstraint]? = nil

func foo() 
    if needsToHideView2 
        constraints = view2.constraints
        NSLayoutConstraint.deactivate(view2.constraints)
    
    if needsToShowView2 
        NSLayoutConstraint.activate(constraints!)
    

【讨论】:

【参考方案2】:

我正在情节提要中进行设置

基本上,你不能。您将不得不使用代码来管理这些约束。当您隐藏 Label2 时,还要换出第一组约束并换入第二组约束。当您显示 Label2 时,还要换出第二组约束并换入第一组约束。这是完全标准的程序。

事实上,我有一个示例项目,它有效地展示了如何完全按照您的描述进行操作:

https://github.com/mattneub/Programming-ios-Book-Examples/blob/master/bk2ch01p032constraintSwapping/ConstraintSwapping/ViewController.swift

如您所见,我们预先配置了视图 v2 何时存在和不存在时的约束,并在我们删除或重新插入 v2 时交换它们。

【讨论】:

【参考方案3】:

不幸的是,隐藏视图只会影响UIStackView 中的关联约束。这是因为UIStackView 在隐藏视图时会自动添加和删除约束。

解决此问题的最佳方法是设置两组约束并根据需要添加/删除每组。我通常在 故事板,并且默认情况下未安装一组。然后我为每个涉及的约束创建IBOutlets,以便我可以轻松地在代码中引用它们:

if button.isHidden 
    self.view.addConstraint(self.hiddenConstraint)
    self.view.removeConstraint(self.visibleConstraint)      
 else 
    self.view.removeConstraint(self.hiddenConstraint)
    self.view.addConstraint(self.visibleConstraint)

【讨论】:

“很遗憾,隐藏视图不会影响关联的约束” 如果视图是 UIStackView 中的排列视图,则会影响。 是的。但这只是因为 UIStackView 正在为您添加和删除约束。我将进行编辑以在技术上更准确... 当然是这样。这对 OP 没有帮助,因为他的约束也需要以比您希望在堆栈视图中配置更复杂的方式进行更改。【参考方案4】:

如果在您的情况下是合理的,请设置您的情节提要同时使用 Label1 和 Label2 并且布局都处于活动状态。

对于V:[Label1]-10-[Label2]-20-|,将 Label2 前导和尾随约束优先级设置为所需 (1000)

对于V:[Label1]-15-|,将Label1 尾随约束设置为较低(可能为750)

然后,在某个适当的地方(viewDidLoad、layoutSubviews、updateConstraints 等),如果您不需要 Label2,只需将其从其父视图中删除即可。

【讨论】:

以上是关于iOS:具有隐藏视图的布局约束的主要内容,如果未能解决你的问题,请参考以下文章

iOS 自动布局约束:忽略隐藏或零尺寸视图?

“隐藏”具有自动布局子视图的 UIView

启用自动布局的 iOS 调整视图大小

自动布局如何在具有 3 个等宽视图的视图中隐藏 1 个视图

具有等宽约束的 iOS 隐藏按钮

如何在 UIStackView 中保留隐藏视图的约束