Search code examples
iosswiftuiviewautolayoutnslayoutconstraint

How to change Auto Layout constraints after they are set when using constraintEqualToAnchor()?


I try to set up a view with AutoLayout constraints by using constraintEqualToAnchor():

override func viewDidLoad() {
    super.viewDidLoad()

    let myView = UIView()
    myView.backgroundColor = UIColor.orangeColor()
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)

    myView.leftAnchor.constraintEqualToAnchor(view.leftAnchor).active = true
    myView.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor).active = true
    myView.topAnchor.constraintEqualToAnchor(view.topAnchor).active = true
    myView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor).active = true

    /******************************************/
    /* I try to change one of the constraints */
    /******************************************/
    myView.leftAnchor.constraintEqualToAnchor(view.rightAnchor, constant: -100).active = true  
}

In the last line of code, I try to change one of the constraints. I thought it would work but it gives some error in the console log

"<NSLayoutConstraint:0x7fb53a5180d0 H:|-(0)-[UIView:0x7fb53a5190b0](LTR)   (Names: '|':UIView:0x7fb53a519240 )>",
"<NSLayoutConstraint:0x7fb53a51f660 H:[UIView:0x7fb53a519240]-(-100)-[UIView:0x7fb53a5190b0](LTR)>",
"<NSLayoutConstraint:0x7fb53a711ee0 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7fb53a519240(414)]>"

When using constraintEqualToAnchor()?, what's the right way to change the constraint later after I have set them?


Solution

  • You need to deactivate the previous constraint when activating a new one so that you don't end up over constraining your view. To do that, store a reference to each of the constraints as a property in your ViewController and then set the active property of the old constraint to false before creating and activating the new constraint:

    Swift 2.x:

    class ViewController: UIViewController {
        var leftConstraint: NSLayoutConstraint?
        var trailingConstraint: NSLayoutConstraint?
        var topConstraint: NSLayoutConstraint?
        var bottomConstraint: NSLayoutConstraint?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let myView = UIView()
            myView.backgroundColor = UIColor.orangeColor()
            myView.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(myView)
    
            leftConstraint = myView.leftAnchor.constraintEqualToAnchor(view.leftAnchor)
            leftConstraint?.active = true
    
            trailingConstraint = myView.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor)
            trailingConstraint?.active = true
    
            topConstraint = myView.topAnchor.constraintEqualToAnchor(view.topAnchor)
            topConstraint?.active = true
    
            bottomConstraint = myView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor)
            bottomConstraint?.active = true
    
            /******************************************/
            /* I try to change one of the constraints */
            /******************************************/
            leftConstraint?.active = false
            leftConstraint = myView.leftAnchor.constraintEqualToAnchor(view.rightAnchor, constant: -100)
            leftConstraint?.active = true
        }
    }
    

    Update for Swift 3 syntax:

    class ViewController: UIViewController {
        var leftConstraint: NSLayoutConstraint?
        var trailingConstraint: NSLayoutConstraint?
        var topConstraint: NSLayoutConstraint?
        var bottomConstraint: NSLayoutConstraint?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let myView = UIView()
            myView.backgroundColor = UIColor.orange
            myView.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(myView)
    
            leftConstraint = myView.leftAnchor.constraint(equalTo: view.leftAnchor)
            leftConstraint?.isActive = true
    
            trailingConstraint = myView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
            trailingConstraint?.isActive = true
    
            topConstraint = myView.topAnchor.constraint(equalTo: view.topAnchor)
            topConstraint?.isActive = true
    
            bottomConstraint = myView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
            bottomConstraint?.isActive = true
    
            /******************************************/
            /* I try to change one of the constraints */
            /******************************************/
            leftConstraint?.isActive = false
            leftConstraint = myView.leftAnchor.constraint(equalTo: view.rightAnchor, constant: -100)
            leftConstraint?.isActive = true
        }
    }