How to update anchor constraint in swift

6.8k Views Asked by At

I would like to create a menu like android in iOS. I'm using layout constraints to setup constraints. I'm facing the issue when I'm trying to update the left constraint of an image on button click (It should animate to clicked button's position). Can anyone help me? It should support landscape and portrait.

I don't want to user third party code and don't want to use the NSLayoutconstraint.

Landscape image Potrait Image

Here is my code.

class MenuViewController: UIViewController {
            var buttons: [UIButton] = []
            var imageView : UIImageView!

            override func viewDidLoad() {
                super.viewDidLoad()
            }

            override func viewDidAppear(_ animated: Bool) {
                super.viewDidAppear(animated)
                addMenuItems()
            }

            func addMenuItems() {

                for _ in 0...4 {
                    let button : UIButton = UIButton()
                    self.view.addSubview(button)
                    button.backgroundColor = UIColor.darkGray
                    button.addTarget(self, action: #selector(didSelectedButton(_:)), for: .touchUpInside)
                    self.buttons.append(button)

                }

                for (index, button) in buttons.enumerated() {

                    button.setTitle(" \(index)", for: .normal)
                    if index == 0 {
                        button.translatesAutoresizingMaskIntoConstraints = false
                        button.leftAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leftAnchor, constant: 0).isActive = true
                        button.widthAnchor.constraint(greaterThanOrEqualToConstant: 1).isActive = true
                        button.heightAnchor.constraint(equalToConstant: 50).isActive = true
                        button.topAnchor.constraint(equalTo: self.view.topAnchor, constant:200).isActive = true

                        self.imageView = UIImageView()
                        self.view.addSubview(self.imageView)
                        self.imageView.backgroundColor = UIColor.red

                        self.imageView.translatesAutoresizingMaskIntoConstraints = false
                        self.imageView.leftAnchor.constraint(equalTo: button.leftAnchor, constant: 0).isActive = true
                        self.imageView.widthAnchor.constraint(equalTo: button.widthAnchor, multiplier: 1).isActive = true
                        self.imageView.heightAnchor.constraint(equalToConstant: 4).isActive = true
                        self.imageView.topAnchor.constraint(equalTo: self.view.topAnchor, constant:250).isActive = true

                    }
                    else {

                        let preButton = buttons\[index - 1\]
                        button.translatesAutoresizingMaskIntoConstraints = false
                        button.leftAnchor.constraint(equalTo: preButton.rightAnchor, constant: 0).isActive = true
                        button.widthAnchor.constraint(equalTo: preButton.widthAnchor, multiplier: 1).isActive = true
                        button.heightAnchor.constraint(equalToConstant: 50).isActive = true
                        button.topAnchor.constraint(equalTo: self.view.topAnchor, constant:200).isActive = true
                        if index == self.buttons.count - 1 {
                            button.rightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.rightAnchor, constant: 0).isActive = true
                        }
                    }

                }

            }

            @objc func didSelectedButton(_ button:UIButton) {
                UIView.animate(withDuration: 1, animations: {
                    self.imageView.leftAnchor.constraint(equalTo: button.leftAnchor).isActive = true
                    self.imageView.layoutIfNeeded()
                }, completion: nil)
            }

        }
1

There are 1 best solutions below

5
On BEST ANSWER

Using anchors creates NSLayoutContraints. You need to deactivate the previous ones when you create new ones.

Add this property to your MenuViewController:

var imageLeftConstraint: NSLayoutConstraint?

Set it when you first create the constraint:

imageLeftConstraint = self.imageView.leftAnchor.constraint(equalTo: button.leftAnchor, constant: 0)
imageLeftConstraint?.isActive = true

Then use it to deactivate the previous constraint before adding a new one:

@objc func didSelectedButton(_ button:UIButton) {
    imageLeftConstraint?.isActive = false
    imageLeftConstraint = self.imageView.leftAnchor.constraint(equalTo: button.leftAnchor)
    imageLeftConstraint?.isActive = true
    UIView.animate(withDuration: 1, animations: {
        self.view.layoutIfNeeded()
    }, completion: nil)
}

Note: You need to call layoutIfNeeded() on the superView of imageView (aka self.view) because the constraint between button and imageView will be added to their common ancestor (self.view).