K1llarney
K1llarney

Reputation: 93

Swift - Programmatically Change Constraints

I am trying to 'show' & 'hide' a collection view by manipulating the constraints programmatically.

My app is written in code, no storyboards or @IBOutlets are being used.

The first time I press the button, the collection view appears correctly and as expected.

The second time I press the button, the collection view just stays in place and does not 'hide'.

The print statements within the openMenu code are confirming that each block of constraints is being called. ie: I get console messages for 'open' and 'closed'.

I don't have an issue with creating the collection view, it's just that setting the constraints programmatically does not close the menu.

My code is as follows...

override func viewDidLoad() {
    super.viewDidLoad()

    navigationController?.isNavigationBarHidden = false

    view.backgroundColor = .white

    view.addSubview(bgImageView)

    view.addSubview(myListCV)
}

lazy var myListCV: UICollectionView = {

    let myListLayout = UICollectionViewFlowLayout()
    myListLayout.itemSize = CGSize(width: 200, height: 40)
    myListLayout.minimumLineSpacing = 1
    myListLayout.sectionHeadersPinToVisibleBounds = true

    let myListView = UICollectionView(frame: .zero, collectionViewLayout: myListLayout)
    myListView.translatesAutoresizingMaskIntoConstraints = false
    myListView.delegate = self
    myListView.dataSource = self

    myListView.bounces = false
    myListView.alwaysBounceVertical = false
    myListView.showsVerticalScrollIndicator = true
    myListView.backgroundColor = UIColor(r: 203, g: 203, b: 203)

    return myListView
}()

var menuShowing = false

func openMenu() {

    if (menuShowing) {
        print("closed")
        myListCV.leftAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        myListCV.topAnchor.constraint(equalTo: view.topAnchor, constant: 64).isActive = true
        myListCV.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        myListCV.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

    } else {
        print("open")
        myListCV.leftAnchor.constraint(equalTo: view.rightAnchor, constant: -200).isActive = true
        myListCV.topAnchor.constraint(equalTo: view.topAnchor, constant: 64).isActive = true
        myListCV.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        myListCV.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    }

    menuShowing = !menuShowing
}

Upvotes: 2

Views: 1623

Answers (1)

WsCandy
WsCandy

Reputation: 420

The problem with your above code is that you are continually setting constraints every time the user opens or closes the the section, so depending on how many times the user does this you'll end up with hundreds of constrains that just aren't needed.

What you should do is set the constraints for the default state, I'm assuming closed in this instance, and store the constraint you wish to change in a property. You can then simply adjust the constant of this constraint to show/hide your menu.

e.g.

private var myListCVLeftConstraint: NSLayoutConstraint?

override func viewDidLoad() {
    super.viewDidLoad()

    navigationController?.isNavigationBarHidden = false

    view.backgroundColor = .white

    view.addSubview(bgImageView)

    self.configMyListCV()
}

lazy var myListCV: UICollectionView = {

    let myListLayout = UICollectionViewFlowLayout()
    myListLayout.itemSize = CGSize(width: 200, height: 40)
    myListLayout.minimumLineSpacing = 1
    myListLayout.sectionHeadersPinToVisibleBounds = true

    let myListView = UICollectionView(frame: .zero, collectionViewLayout: myListLayout)
    myListView.translatesAutoresizingMaskIntoConstraints = false
    myListView.delegate = self
    myListView.dataSource = self

    myListView.bounces = false
    myListView.alwaysBounceVertical = false
    myListView.showsVerticalScrollIndicator = true
    myListView.backgroundColor = UIColor(r: 203, g: 203, b: 203)

    return myListView
}()

var menuShowing = false

private func configMyListCV() -> Void {

    view.addSubview(myListCV)

    self.myListCV.topAnchor.constraint(equalTo: view.topAnchor, constant: 64).isActive = true
    self.myListCV.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
    self.myListCV.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

    self.myListCVLeftConstraint = myListCV.leftAnchor.constraint(equalTo: view.rightAnchor)
    self.myListCVLeftConstraint.isActive = true
}

func openMenu() {

    if (menuShowing) {

        self.myListCVLeftConstraint?.constant = 0.0

    } else {

        self.myListCVLeftConstraint?.constant = -200.0

    }

    menuShowing = !menuShowing
}

This will work well for this simple user case; however if you do anything more in depth in the future I'd suggest setting multiple constraints on the view and simply disable/enable the required ones as needed.

Upvotes: 3

Related Questions