当视图大小不同时如何以编程方式设置约束?

How to programmatically set constraints when View sizes are different?

使用 Xcode 10,iOS 11.4+,Swift 4

我正在浏览一系列 UIViewController, 每个都被放入一个 ContainerView 中。

基于VC被推送,我hiding/showing主控制器中的顶部或底部视图(以灰色显示),而ContainerView始终在中间(浅蓝色)。

我想做的是设置约束,以便在顶视图或底视图为 shown/hidden 时适当调整 ContainerView 的大小。

例如,当 "Main Menu" 显示时,ContainerView 应填充整个 Main Container 视图(Top 和 Bottom 视图将被隐藏)

显示"Item1"时,会显示顶视图,隐藏底视图。因此,ContainerView 应填充 Main Container 视图的左、右和底部,但 ContainerView Top 应限制在 Top 视图底部。

显示 "Item5" 时,顶视图和底视图也会显示。 因此,ContainerView应该填充Main Container view left, right,并被约束在Top view bottom,Bottom view top(如Main Container所示)

我试过使用这样的代码来填充整个主视图:

NSLayoutConstraint.activate([
   ContainerView.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 0),
   ContainerView.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: 0),
   ContainerView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0),
   ContainerView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0)
])

但是,ContainerView 永远不会改变,Xcode 给了我很多警告,例如:

[LayoutConstraints] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want.

这是情节提要中的另一个屏幕截图:

这里是 link 下载我的示例项目: https://gitlab.com/whoit/containerviews

如何正确修改约束以实现此目的?

正如我在评论中提到的,您应该使用 UIStackView 来控制顶部/底部视图的可见性。

您需要 UIStackView 具有以下属性:

  • 轴:垂直
  • 对齐方式:填充
  • 分配:填充
  • 间距:根据您的需要

堆栈视图将分别包含顶部视图容器视图底部视图作为其子视图。

您需要将此堆栈视图的所有边(前导、尾随、顶部和底部)固定到其父视图(视图控制器的视图)。由于您的顶视图和底视图需要一些高度限制,因此您可以根据需要提供它们。


所以基本上,当您隐藏其中任何一个时,您的堆栈视图现在能够调整其子视图的大小。您只需要执行:

theSubViewNeedsTobeHidden.isHidden = true

我已经为您制作了一个可以工作的演示 here

问题

1) 你一直在添加新的约束,因为这行创建了一个新的约束,每次它们被调用时:

ContainerView.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 0)

2) 一开始,MainContainerView 根本不是约束

解决方案

我建议如下:

  • 改为在故事板中添加这四个约束
  • 为顶部和底部视图的高度限制创建 IBOutlets。
  • 将它们的 constant 设置为 0(隐藏它们时)
  • (可选)当然你仍然可以通过设置它们的 alpha 来淡化它们 in/out,然后将高度常量添加到完成块。

注意: 布局时仍会考虑隐藏视图(alpha = 0isHidden = true)。这意味着,当视图被隐藏时,您的约束仍然有效。但是为了使它们在布局中看起来也隐藏起来,您必须将它们的高度 constants 设置为 0.

代码

@objc func hideControlViews(_ notification: Notification){
    let userInfo = notification.userInfo! as! [String : Bool]
    //print("Got top view notification: \(String(describing: userInfo["hide"]))")
    if (userInfo["hidetop"]!) {
        self.topViewHeightConstraint.constant = 0
    } else {
        self.topViewHeightConstraint.constant = 64
    }
    if (userInfo["hidebottom"]!) {
        self.bottomViewHeightConstraint.constant = 0
    } else {
        self.bottomViewHeightConstraint.constant = 108
    }

    self.view.layoutIfNeeded()
}