ios - How to use Auto Layout to move other views when a view is hidden?

ID : 7906

viewed : 129

Tags : iosiphonecocoa-touchinterface-builderautolayoutios





Top 5 Answer for ios - How to use Auto Layout to move other views when a view is hidden?

vote vote

92

It is possible, but you'll have to do a little extra work. There are a couple conceptual things to get out of the way first:

  • Hidden views, even though they don't draw, still participate in Auto Layout and usually retain their frames, leaving other related views in their places.
  • When removing a view from its superview, all related constraints are also removed from that view hierarchy.

In your case, this likely means:

  • If you set your left view to be hidden, the labels stay in place, since that left view is still taking up space (even though it's not visible).
  • If you remove your left view, your labels will probably be left ambiguously constrained, since you no longer have constraints for your labels' left edges.

What you need to do is judiciously over-constrain your labels. Leave your existing constraints (10pts space to the other view) alone, but add another constraint: make your labels' left edges 10pts away from their superview's left edge with a non-required priority (the default high priority will probably work well).

Then, when you want them to move left, remove the left view altogether. The mandatory 10pt constraint to the left view will disappear along with the view it relates to, and you'll be left with just a high-priority constraint that the labels be 10pts away from their superview. On the next layout pass, this should cause them to expand left until they fill the width of the superview but for your spacing around the edges.

One important caveat: if you ever want your left view back in the picture, not only do you have to add it back into the view hierarchy, but you also have to reestablish all its constraints at the same time. This means you need a way to put your 10pt spacing constraint between the view and its labels back whenever that view is shown again.

vote vote

82

Adding or removing constraints during runtime is a heavyweight operation that can affect performance. However, there is a simpler alternative.

For the view you wish to hide, set up a width constraint. Constrain the other views with a leading horizontal gap to that view.

To hide, update the .constant of the width constraint to 0.f. The other views will automatically move left to assume position.

See my other answer here for more details:

How to change label constraints during runtime?

vote vote

78

For those who support iOS 8+ only, there is a new boolean property active. It will help to enable only needed constraints dynamically

P.S. Constraint outlet must be strong, not weak

Example:

@IBOutlet weak var optionalView: UIView! @IBOutlet var viewIsVisibleConstraint: NSLayoutConstraint! @IBOutlet var viewIsHiddenConstraint: NSLayoutConstraint!  func showView() {     optionalView.isHidden = false     viewIsVisibleConstraint.isActive = true     viewIsHiddenConstraint.isActive = false }  func hideView() {     optionalView.isHidden = true     viewIsVisibleConstraint.isActive = false     viewIsHiddenConstraint.isActive = true } 

Also to fix an error in storyboard you'll need to uncheck Installed checkbox for one of these constraints.

UIStackView (iOS 9+)
One more option is to wrap your views in UIStackView. Once view is hidden UIStackView will update layout automatically

vote vote

61

UIStackView repositions its views automatically when the hidden property is changed on any of its subviews (iOS 9+).

UIView.animateWithDuration(1.0) { () -> Void in    self.mySubview.hidden = !self.mySubview.hidden } 

Jump to 11:48 in this WWDC video for a demo:

Mysteries of Auto Layout, Part 1

vote vote

56

My project uses a custom @IBDesignable subclass of UILabel (to ensure consistency in colour, font, insets etc.) and I have implemented something like the following:

override func intrinsicContentSize() -> CGSize {     if hidden {         return CGSizeZero     } else {         return super.intrinsicContentSize()     } } 

This allows the label subclass to take part in Auto Layout, but take no space when hidden.

Top 3 video Explaining ios - How to use Auto Layout to move other views when a view is hidden?







Related QUESTION?