Ungo2021
Ungo2021

Reputation: 5

Ambiguous Layout (Programmatically Added Constraint)

I don't know why my programmatically created constraints are ambiguous. My app has two container views inside a stackview. One of the container views kanjiView acts as drop down window below the navigation bar. Can someone please point me to the right direction?

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),
    ])
}

This is the function used to hide the kanjiView:

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

Here's the output warning in the console:

(
    "<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)>

Upvotes: 0

Views: 307

Answers (2)

flanker
flanker

Reputation: 4210

You seem to be anchoring the top and bottom of your stackview to the layoutMArginGuide, which inherently sets the height, and also setting the height manually. At best, if the two values match exactly, this is overkill, and if they differ by a fraction of a point it'll create an unsatifiable constraint. Lose the explicit height constraints.

Upvotes: 1

Steve Christensen
Steve Christensen

Reputation: 41

I'm not sure if this is the issue or not, but in your NSLayoutConstraint.activate() you are setting both anchors and edge constraints for stackView. Pick one or the other, not both.

Upvotes: 0

Related Questions