Heuristic
Heuristic

Reputation: 5341

iOS: layout constraint with hidden views

Say I have two views aligned to bottom:

V:[Label1]-10-[Label2]-20-|

There is 10 points spacing between Label1 and Label2, 20 points spacing between Label2 and bottom.

Now, in some cases, I need to hide Label2, and in this case, I want to have:

V:[Label1]-15-|

That is, with Label2 being hidden, Label1 has 15 points spacing to bottom.

I'm setting this up in storyboard, I'm thinking of making the 15 points spacing having lower priority and hide Label2 as needed, but it doesn't seem to work.

What is the best way to achieve this?

Thanks!

Upvotes: 3

Views: 4347

Answers (4)

JBJr
JBJr

Reputation: 109

If it's reasonable in your situation, set up your storyboard with both Label1 and Label2 and BOTH the layouts active.

For V:[Label1]-10-[Label2]-20-| set Label2 leading and trailing constraint priorities to required (1000)

For V:[Label1]-15-| set Label1 trailing constraint lower (maybe 750)

Then, at some appropriate place (viewDidLoad, layoutSubviews, updateConstraints, etc.), if you don't need Label2, just remove it from its superview.

Upvotes: 0

Jake
Jake

Reputation: 13753

Unfortunately, hiding a view only affects associated constraints in a UIStackView. This is the case because UIStackView adds and removes constraints automatically when a view is hidden.

The best way to approach this is by having two sets of constraints and adding/removing each set as needed. I usually create these constraints in a storyboard and have one set not installed by default. I then create IBOutlets to each constraint involved so that I can easily reference them in code:

if button.isHidden {
    self.view.addConstraint(self.hiddenConstraint)
    self.view.removeConstraint(self.visibleConstraint)      
} else {
    self.view.removeConstraint(self.hiddenConstraint)
    self.view.addConstraint(self.visibleConstraint)
}

Upvotes: 0

matt
matt

Reputation: 535202

I'm setting this up in storyboard

Basically, you can't. You will have to use code to manage these constraints. When you hide Label2, also swap out the first set of constraints and swap in the second ones. When you show Label2, also swap out the second set of constraints and swap in the first ones. This is perfectly standard procedure.

In fact, I have an example project that effectively shows how to do exactly what you're describing:

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch01p032constraintSwapping/ConstraintSwapping/ViewController.swift

As you can see, we configure in advance the constraints for when the view v2 is present and for when it is absent, and just swap them when we remove or reinsert v2.

Upvotes: 0

andrehungaro
andrehungaro

Reputation: 525

By keeping that low priority constraint you mentioned, the shorter solution I've found for that was:

@IBOutlet weak var view2: UIView!
var constraints: [NSLayoutConstraint]? = nil

func foo() {
    if needsToHideView2 {
        constraints = view2.constraints
        NSLayoutConstraint.deactivate(view2.constraints)
    }
    if needsToShowView2 {
        NSLayoutConstraint.activate(constraints!)
    }
}

Upvotes: 1

Related Questions