Search code examples
iosswiftnslayoutconstraint

How to update constraints dynamically?


I have three UIButton, I have created programmatically constraints, at some condition i am removing one of UIButton as button.removeFromSuperview() & rest of two button will set constraints as per priorities. Issue is when i am removing one UIButton(buttonWink) then as of viewLifeCycle viewWillLayoutSubviews will called & App crashes in below line

 buttonWink.translatesAutoresizingMaskIntoConstraints = false

Ofcourse because buttonWink is removed from superview however we can check before setting constraints as

  if buttonWink != nil {
        buttonWink.translatesAutoresizingMaskIntoConstraints = false
      }

But by checking nil for every button will make code lengthy, is there any way of doing the same? i will really appreciate friends.

Output -

enter image description here

Here i am attaching my tried full code.

import UIKit
class MasterViewController: UIViewController {
    @IBOutlet weak var buttonMessage : UIButton!
    @IBOutlet weak var buttonLike : UIButton!
    @IBOutlet weak var buttonWink : UIButton!
    @IBAction func tapsOnLike(_ sender: UIButton) {
        sender.removeFromSuperview()
    }
    @IBAction func tapsOnWink(_ sender: UIButton) {
        sender.removeFromSuperview()
    }
    @IBAction func tapsOnNextButton(){
        let vc = DetailViewController(nibName: "DetailViewController", bundle: nil)
        navigationController?.pushViewController(vc, animated: true)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
       setConstraints()
        navigationController?.isNavigationBarHidden = true
    }
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(true)
       // setConstraints()
    }
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        //setConstraints()
    }
    func setConstraints() {

        if buttonMessage != nil {
            buttonMessage?.translatesAutoresizingMaskIntoConstraints = false
        }
            buttonLike?.translatesAutoresizingMaskIntoConstraints = false
            buttonWink?.translatesAutoresizingMaskIntoConstraints = false

        //Constraints for Message button

        let leading = NSLayoutConstraint(item: buttonMessage, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 8)
        leading.isActive = true

        let trailingToSuperView = NSLayoutConstraint(item: buttonMessage, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: -8)

        trailingToSuperView.priority = 998
        trailingToSuperView.isActive = true

        let bottomToSuperView = NSLayoutConstraint(item: buttonMessage, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: -8)
        bottomToSuperView.isActive = true


        let trailingToWink = NSLayoutConstraint(item: buttonMessage, attribute: .trailing, relatedBy: .equal, toItem: buttonWink, attribute: .leading, multiplier: 1, constant: -8)
        trailingToWink.priority = 999
        trailingToWink.isActive = true

        let leadingToLike = NSLayoutConstraint(item: buttonMessage, attribute: .trailing, relatedBy: .equal, toItem: buttonLike, attribute: .leading, multiplier: 1.0, constant: -8)
        leadingToLike.isActive = true

        let alignBottomToWink = NSLayoutConstraint(item: buttonMessage, attribute: .bottom, relatedBy: .equal, toItem: buttonWink, attribute: .bottom, multiplier: 1, constant: 0)
        alignBottomToWink.isActive = true

        let alignBottomToLike = NSLayoutConstraint(item: buttonMessage, attribute: .bottom, relatedBy: .equal, toItem: buttonLike, attribute: .bottom, multiplier: 1, constant: 0)
        alignBottomToLike.isActive = true


        let equalWidthToWink = NSLayoutConstraint(item: buttonMessage, attribute: .width, relatedBy: .equal, toItem: buttonWink, attribute: .width, multiplier: 1, constant: 0)
        equalWidthToWink.isActive = true


        let equalWidthToLike = NSLayoutConstraint(item: buttonMessage, attribute: .width, relatedBy: .equal, toItem: buttonLike, attribute: .width, multiplier: 1, constant: 0)
        equalWidthToLike.isActive = true

        //Constraints for like button
        let trailingLikeToSuperView = NSLayoutConstraint(item: buttonLike, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: -8)
        trailingLikeToSuperView.priority = 999
        trailingLikeToSuperView.isActive = true
        let leadingToWink = NSLayoutConstraint(item: buttonLike, attribute: .trailing, relatedBy: .equal, toItem: buttonWink, attribute: .leading, multiplier: 1.0, constant: -8)
        leadingToWink.isActive = true


        //Constraints for Wink button
        let trailingWinkToSuperView = NSLayoutConstraint(item: buttonWink, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: -8)
        trailingWinkToSuperView.isActive = true

    }

}

Solution

  • I just added UIStackView & it's too easy, Three buttons are added in horizontal stack view with 8 points spacing & added three constraints to stack view as leading, trailing & bottom to superview

    enter image description here

    @IBOutlet weak var stackView: UIStackView!
    @IBAction func tapsOnLikeInStack(_ sender: UIButton) {
        sender.isHidden = true
    }
    @IBAction func tapsOnWinkInStack(_ sender: UIButton) {
        sender.isHidden = true
    }
    
    func constraintsForStackView(){
        stackView?.translatesAutoresizingMaskIntoConstraints = false
        stackView.spacing = 8
        stackView.axis = .horizontal
        stackView.distribution = .fillEqually
        stackView.alignment = .fill
    
        let leading = NSLayoutConstraint(item: stackView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 8)
        leading.isActive = true
        let trailingToSuperView = NSLayoutConstraint(item: stackView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: -8)
        trailingToSuperView.isActive = true
        let bottomToSuperView = NSLayoutConstraint(item: stackView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: -120)
        bottomToSuperView.isActive = true
    }