Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AutoLayout with hidden UIViews?

People also ask

What is a stack view iOS?

Overview. Stack views let you leverage the power of Auto Layout, creating user interfaces that can dynamically adapt to the device's orientation, screen size, and any changes in the available space. The stack view manages the layout of all the views in its arrangedSubviews property.


My personal preference for showing/hiding views is to create an IBOutlet with the appropriate width or height constraint.

I then update the constant value to 0 to hide, or whatever the value should be to show.

The big advantage of this technique is that relative constraints will be maintained. For example let's say you have view A and view B with a horizontal gap of x. When view A width constant is set to 0.f then view B will move left to fill that space.

There's no need to add or remove constraints, which is a heavyweight operation. Simply updating the constraint's constant will do the trick.


The solution of using a constant 0 when hidden and another constant if you show it again is functional, but it is unsatisfying if your content has a flexible size. You'd need to measure your flexible content and set a constant back. This feels wrong, and has issues if content changes size because of server or UI events.

I have a better solution.

The idea is to set the a 0 height rule to have high priority when we hide the element so that it takes up no autolayout space.

Here's how you do that:

1. set up a width (or height) of 0 in interface builder with a low priority.

setting width 0 rule

Interface Builder won't yell about conflicts because the priority is low. Test the height behavior by setting the priority to 999 temporarily (1000 is forbidden to mutate programmatically, so we won't use it). Interface builder will probably now yell about conflicting constraints. You can fix these by setting priorities on related objects to 900 or so.

2. Add an outlet so you can modify the priority of the width constraint in code:

outlet connection

3. Adjust the priority when you hide your element:

cell.alertTimingView.hidden    = place.closingSoon != true
cell.alertTimingWidth.priority = place.closingSoon == true ? 250 : 999

UIStackView is probably the way to go for iOS 9+. Not only does it handle the hidden view, it will also remove additional spacing and margins if set up correctly.


In this case, I map the height of the Author label to an appropriate IBOutlet:

@property (retain, nonatomic) IBOutlet NSLayoutConstraint* authorLabelHeight;

and when I set the height of the constraint to 0.0f, we preserve the "padding", because the Play button's height allows for it.

cell.authorLabelHeight.constant = 0; //Hide 
cell.authorLabelHeight.constant = 44; //Show

enter image description here


There's a lot of solutions here but my usual approach is different again :)

Set up two sets of constraints similar to Jorge Arimany's and TMin's answer:

enter image description here

All three marked constraints have a the same value for the Constant. The constraints marked A1 and A2 have their Priority set to 500, while the constraint marked B has it's Priority set to 250 (or UILayoutProperty.defaultLow in code).

Hook up constraint B to an IBOutlet. Then, when you hide the element, you just need to set the constraint priority to high (750):

constraintB.priority = .defaultHigh

But when the element is visible, set the priority back to low (250):

constraintB.priority = .defaultLow

The (admittedly minor) advantage to this approach over just changing isActive for constraint B is that you still have a working constraint if the transient element gets removed from the view by other means.