Home > Mobile >  How to Constraint Two UI Elements to same place - Swift iOS
How to Constraint Two UI Elements to same place - Swift iOS

Time:07-30

I'm attempting to constrain two ui elements to the same place. At the beginning of my program, I'm constraining a label to the center of a UiView. This is working fine. However later in my program, I'm attempting to remove this label from the UiView and constrain a button to the center of the same UiView. However, when I begin constraining my button, the system errors out.

How do you constrain two ui elements to the same place in Swift?

Here's the relevant code.

override func viewDidLoad() {
    super.viewDidLoad()
     // Middle UI View
    view.addSubview(middleUIView)
    
    NSLayoutConstraint.activate([
        middleUIView.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor),
        middleUIView.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor),
        middleUIView.topAnchor.constraint(equalTo: sosButton.bottomAnchor),
        middleUIView.bottomAnchor.constraint(equalTo: textView.topAnchor)
    ])
    
    // Middle Label
    middleUIView.addSubview(middleUILabel)
    
    NSLayoutConstraint.activate([
        middleUILabel.centerXAnchor.constraint(equalTo: middleUIView.centerXAnchor),
        middleUILabel.centerYAnchor.constraint(equalTo: middleUIView.centerYAnchor)
    ])
}
func createButton() {
    middleUILabel.removeFromSuperview()
        middleUIView.removeConstraints(middleUIView.constraints)
        

        // It errors out here 
        NSLayoutConstraint.activate([
            continueButton.widthAnchor.constraint(equalToConstant: 150),
            continueButton.heightAnchor.constraint(equalToConstant: 50),
            
            continueButton.centerXAnchor.constraint(equalTo: middleUIView.centerXAnchor),
            continueButton.centerYAnchor.constraint(equalTo: middleUIView.centerYAnchor)
        ])
}

This is the error:

Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with anchors <NSLayoutXAxisAnchor:0x2807ffd80 "UIButton:0x135425fc0'Continue'.centerX"> and <NSLayoutXAxisAnchor:0x2807d4b00 "UIView:0x135425700.centerX"> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal.'

CodePudding user response:

You need to add your button to the view hierarchy before adding contraints to it.

Also, you should keep track of the constraints you created for the label so that you can call NSContraint.deactivate() on them before you remove the label.

var labelConstraints: [NSLayoutConstraint] = []

override func viewDidLoad() {
    super.viewDidLoad()
     // Middle UI View
    view.addSubview(middleUIView)
    
    NSLayoutConstraint.activate([
        middleUIView.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor),
        middleUIView.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor),
        middleUIView.topAnchor.constraint(equalTo: sosButton.bottomAnchor),
        middleUIView.bottomAnchor.constraint(equalTo: textView.topAnchor)
    ])
    
    // Middle Label
    middleUIView.addSubview(middleUILabel)
       
    labelConstraints = [
        middleUILabel.centerXAnchor.constraint(equalTo: middleUIView.centerXAnchor),
        middleUILabel.centerYAnchor.constraint(equalTo: middleUIView.centerYAnchor)
    ]
    NSLayoutConstraint.activate(labelConstraints)
}

func createButton() {
    NSLayoutConstraint.deactivate(labelConstraints)
    labelConstraints = []
    middleUILabel.removeFromSuperview()
        
    // Add continue Button to the view hierarchy
    middleUIView.addSubview(continueButton)

    NSLayoutConstraint.activate([
        continueButton.widthAnchor.constraint(equalToConstant: 150),
        continueButton.heightAnchor.constraint(equalToConstant: 50),
            
        continueButton.centerXAnchor.constraint(equalTo: middleUIView.centerXAnchor),
        continueButton.centerYAnchor.constraint(equalTo: middleUIView.centerYAnchor)
    ])
}

Note: Manually removing constraints from views (like middleUIView.removeConstraints(middleUIView.constraints)) is not recommended because you might remove constraints you didn't know were there. In general, you should just activate() and deactivate() constraints and let the system add them to and remove them from the proper views for you.

  • Related