不明确的布局(以编程方式添加的约束)

Ambiguous Layout (Programmatically Added Constraint)

我不知道为什么我以编程方式创建的约束不明确。我的应用程序在堆栈视图中有两个容器视图。其中一个容器视图 kanjiView 充当导航栏下方的下拉菜单 window。有人可以给我指出正确的方向吗?

override func viewDidLoad() {
    super.viewDidLoad()

    // Add Kanji View Container
    let kanjiView = UIView()
    view.addSubview(kanjiView)

    // add child view controller view to container
    let kanjiController = storyboard!.instantiateViewController(withIdentifier: "KanjiDictionaryTab")
    addChild(kanjiController)
    kanjiView.addSubview(kanjiController.view)
    kanjiController.didMove(toParent: self)
    
    // Add Safari View Container
    let safariView = UIView()
    view.addSubview(safariView)

    // add child view controller view to container
    let safariController = storyboard!.instantiateViewController(withIdentifier: "SafariTab")
    addChild(safariController)
    safariView.addSubview(safariController.view)
    safariController.didMove(toParent: self)
    
    //Create StackView
    let stackView = UIStackView()
    stackView.spacing = 0
    stackView.axis = .vertical
    stackView.distribution = .equalSpacing
    stackView.alignment = .center
    
    stackView.addArrangedSubview(kanjiView)
    stackView.addArrangedSubview(safariView)
    view.addSubview(stackView)
    
    //Disable Autoresize
    kanjiView.translatesAutoresizingMaskIntoConstraints = false
    kanjiController.view.translatesAutoresizingMaskIntoConstraints = false
    safariView.translatesAutoresizingMaskIntoConstraints = false
    safariController.view.translatesAutoresizingMaskIntoConstraints = false
    stackView.translatesAutoresizingMaskIntoConstraints = false
    //self.view.translatesAutoresizingMaskIntoConstraints = false
    
    //Add Constraints
    NSLayoutConstraint.activate([
        kanjiController.view.leadingAnchor.constraint(equalTo: kanjiView.leadingAnchor),
        kanjiController.view.trailingAnchor.constraint(equalTo: kanjiView.trailingAnchor),
        kanjiController.view.topAnchor.constraint(equalTo: kanjiView.topAnchor),
        kanjiController.view.bottomAnchor.constraint(equalTo: kanjiView.bottomAnchor),
        
        safariView.widthAnchor.constraint(equalToConstant: self.view.frame.width),
        safariView.heightAnchor.constraint(equalToConstant: self.view.frame.height*3/4),
        kanjiView.widthAnchor.constraint(equalToConstant: self.view.frame.width),
        kanjiView.heightAnchor.constraint(equalToConstant: self.view.frame.height*1/4),
        //kanjiView.heightAnchor.constraint(lessThanOrEqualToConstant: self.view.frame.height*1/4),
        
        safariController.view.leadingAnchor.constraint(equalTo: safariView.leadingAnchor),
        safariController.view.trailingAnchor.constraint(equalTo: safariView.trailingAnchor),
        safariController.view.topAnchor.constraint(equalTo: safariView.topAnchor),
        safariController.view.bottomAnchor.constraint(equalTo: safariView.bottomAnchor),
        
        //stackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
        //stackView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
        stackView.widthAnchor.constraint(equalToConstant: self.view.frame.width),
        stackView.heightAnchor.constraint(equalToConstant: self.view.frame.height),
       
        
        NSLayoutConstraint(item: stackView, attribute: .top, relatedBy: .equal, toItem: view.layoutMarginsGuide, attribute: .top, multiplier: 1.0, constant: 0),
        NSLayoutConstraint(item: stackView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 0),
        NSLayoutConstraint(item: stackView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0),
        NSLayoutConstraint(item: stackView, attribute: .bottom, relatedBy: .equal, toItem: view.layoutMarginsGuide, attribute: .bottom, multiplier: 1, constant: 0),
    ])
}

这是用来隐藏kanjiView的函数:

func hideKanji() {
    UIView.animate(withDuration: 0.35) {
        self.kanjiView.isHidden.toggle()
        self.stackView.layoutIfNeeded()
    }
}

这是控制台中的输出警告:

(
    "<NSLayoutConstraint:0x6000021649b0 UIStackView:0x7ff2d6c12980.height == 844   (active)>",
    "<NSLayoutConstraint:0x600002164cd0 UIStackView:0x7ff2d6c12980.top == UILayoutGuide:0x600003b088c0'UIViewLayoutMarginsGuide'.top   (active)>",
    "<NSLayoutConstraint:0x600002164dc0 UIStackView:0x7ff2d6c12980.bottom == UILayoutGuide:0x600003b088c0'UIViewLayoutMarginsGuide'.bottom   (active)>",
    "<NSLayoutConstraint:0x600002164aa0 'UIView-bottomMargin-guide-constraint' V:[UILayoutGuide:0x600003b088c0'UIViewLayoutMarginsGuide']-(83)-|   (active, names: '|':UIView:0x7ff2f6d1d990 )>",
    "<NSLayoutConstraint:0x600002153480 'UIView-Encapsulated-Layout-Height' UIView:0x7ff2f6d1d990.height == 844   (active)>",
    "<NSLayoutConstraint:0x600002164a00 'UIView-topMargin-guide-constraint' V:|-(91)-[UILayoutGuide:0x600003b088c0'UIViewLayoutMarginsGuide']   (active, names: '|':UIView:0x7ff2f6d1d990 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x6000021649b0 UIStackView:0x7ff2d6c12980.height == 844   (active)>

(
    "<NSLayoutConstraint:0x600002164730 UIView:0x7ff2d6c12810.height == 633   (active)>",
    "<NSLayoutConstraint:0x6000021647d0 UIView:0x7ff2d6c116e0.height == 211   (active)>",
    "<NSLayoutConstraint:0x600002164cd0 UIStackView:0x7ff2d6c12980.top == UILayoutGuide:0x600003b088c0'UIViewLayoutMarginsGuide'.top   (active)>",
    "<NSLayoutConstraint:0x600002164dc0 UIStackView:0x7ff2d6c12980.bottom == UILayoutGuide:0x600003b088c0'UIViewLayoutMarginsGuide'.bottom   (active)>",
    "<NSLayoutConstraint:0x600002151fe0 'UISV-canvas-connection' UIStackView:0x7ff2d6c12980.top == UIView:0x7ff2d6c116e0.top   (active)>",
    "<NSLayoutConstraint:0x6000021533e0 'UISV-canvas-connection' V:[UIView:0x7ff2d6c12810]-(0)-|   (active, names: '|':UIStackView:0x7ff2d6c12980 )>",
    "<NSLayoutConstraint:0x600002153430 'UISV-distributing-edge' V:[UIView:0x7ff2d6c116e0]-(0)-[_UIOLAGapGuide:0x600003e15e00'UISV-distributing']   (active)>",
    "<NSLayoutConstraint:0x600002151f40 'UISV-distributing-edge' _UIOLAGapGuide:0x600003e15e00'UISV-distributing'.bottom == UIView:0x7ff2d6c12810.top   (active)>",
    "<NSLayoutConstraint:0x600002164aa0 'UIView-bottomMargin-guide-constraint' V:[UILayoutGuide:0x600003b088c0'UIViewLayoutMarginsGuide']-(83)-|   (active, names: '|':UIView:0x7ff2f6d1d990 )>",
    "<NSLayoutConstraint:0x600002153480 'UIView-Encapsulated-Layout-Height' UIView:0x7ff2f6d1d990.height == 844   (active)>",
    "<NSLayoutConstraint:0x600002164a00 'UIView-topMargin-guide-constraint' V:|-(91)-[UILayoutGuide:0x600003b088c0'UIViewLayoutMarginsGuide']   (active, names: '|':UIView:0x7ff2f6d1d990 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x600002164730 UIView:0x7ff2d6c12810.height == 633   (active)>

我不确定这是否是问题所在,但在您的 NSLayoutConstraint.activate() 中,您正在为 stackView 设置锚点和边缘约束。选择其中之一,而不是两者。

您似乎将堆栈视图的顶部和底部锚定到本身设置高度的 layoutMArginGuide,并且还手动设置了高度。充其量,如果这两个值完全匹配,那就太过分了,如果它们相差一点点,就会产生无法满足的约束。失去明确的高度限制。