Sean
Sean

Reputation: 341

How to update constraints based on user input

I have a view controller view with 3 column sections (called legs, aView, bView, and cView) by default. The user can switch it between 2 and 3 in a settings menu that gets presented modally over the same screen.

I'm trying to get the columns to take up space equally on the screen, so when there are 3 columns, they each take up roughly 1/3 of the width (ignoring padding), and when there are 2, they each take up roughly 1/2.

My current method is setting some constraints that are always active, and then for the ones that change depending on the number of columns, using an if statement. I tried some variations of layoutIfNeeded(), removeConstraints, and others but not entirely sure how to implement them.

For some clarification on the code, xView is the column view, which contains xTitle and xTextView. There is also a mainButton above the text views, and button1 below the text views. This all exists inside a contentView and scrollView setup.


let sidePadding: CGFloat = 15


func placeViews() { // run in viewWillAppear

        let alwaysConstraints = [
            aView.topAnchor.constraint(equalTo: mainButton.bottomAnchor, constant: 25),
            aView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: sidePadding),
            aView.rightAnchor.constraint(equalTo: bView.leftAnchor),
            bView.topAnchor.constraint(equalTo: aView.topAnchor),
            bView.bottomAnchor.constraint(equalTo: aView.bottomAnchor),
            aTitle.topAnchor.constraint(equalTo: aView.topAnchor),
            bTitle.topAnchor.constraint(equalTo: aTitle.topAnchor),
            aTitle.centerXAnchor.constraint(equalTo: aView.centerXAnchor),
            bTitle.centerXAnchor.constraint(equalTo: bView.centerXAnchor),
            aTextView.topAnchor.constraint(equalTo: aTitle.bottomAnchor, constant: 25),
            bTextView.topAnchor.constraint(equalTo: aTextView.topAnchor),
            aTextView.bottomAnchor.constraint(equalTo: aView.bottomAnchor),
            bTextView.bottomAnchor.constraint(equalTo: aTextView.bottomAnchor),
            aTextView.centerXAnchor.constraint(equalTo: aView.centerXAnchor),
            bTextView.centerXAnchor.constraint(equalTo: bView.centerXAnchor),
            aTextView.widthAnchor.constraint(equalTo: aView.widthAnchor),
            bTextView.widthAnchor.constraint(equalTo: bView.widthAnchor),
            bView.widthAnchor.constraint(equalTo: aView.widthAnchor),

            // Restrict buttons to leg views
            button1.heightAnchor.constraint(equalToConstant: buttonHeight),
            button1.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20),
            button1.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20),
            button1.topAnchor.constraint(equalTo: aView.bottomAnchor, constant: 40),

            // Restrict button to bottom
            button1.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20)
        ]




        let twoLegConstraints = [
            aView.widthAnchor.constraint(equalToConstant: (view.frame.width - (sidePadding * 2) / 2)),
            bView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -sidePadding),
        ]

        let threeLegConstraints = [
            aView.widthAnchor.constraint(equalToConstant: (view.frame.width - (sidePadding * 2)) / 3),
            bView.rightAnchor.constraint(equalTo: cView.leftAnchor),
            cView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -sidePadding),
            cView.topAnchor.constraint(equalTo: aView.topAnchor),
            cView.bottomAnchor.constraint(equalTo: aView.bottomAnchor),
            cTitle.topAnchor.constraint(equalTo: aTitle.topAnchor),
            cTitle.centerXAnchor.constraint(equalTo: cView.centerXAnchor),
            cTextView.topAnchor.constraint(equalTo: aTextView.topAnchor),
            cTextView.bottomAnchor.constraint(equalTo: aTextView.bottomAnchor),
            cTextView.centerXAnchor.constraint(equalTo: cView.centerXAnchor),
            cTextView.widthAnchor.constraint(equalTo: cView.widthAnchor),
            cView.widthAnchor.constraint(equalTo: aView.widthAnchor),
        ]





        NSLayoutConstraint.activate(alwaysConstraints)

        if legs == 2 {
            cView.isHidden = true
            NSLayoutConstraint.activate(twoLegConstraints)
        } else if legs == 3 {
            cView.isHidden = false
            NSLayoutConstraint.activate(threeLegConstraints)
        }
    }

At the moment, the screen starts with 3 by default, and it works perfectly (each ~1/3 screen width). Then the user can switch it to 2, and it works perfectly again (each ~1/2 screen width). Then switching back to 3, the first two don't change at all, and the third column appears on the right edge of the screen.

Upvotes: 0

Views: 50

Answers (1)

EmilioPelaez
EmilioPelaez

Reputation: 19882

Use a stack view with distribution = .fillEqually. It will take care of the layout and constraints automatically when you set the isHidden property of any of your views.

Upvotes: 1

Related Questions