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.
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:
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
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With