Using Size Classes to Hide Stack View Contents

I had an interesting question this week about stack views and size classes that I thought was worth sharing. Suppose you have a stack view containing three views and you want to hide one of them for certain size classes. For example with the vertical stack shown below what if I want to hide the bottom heart view when the device has a compact vertical size class?

Vertical Stack View

The writer was trying to do this using size classes in Interface Builder to control when to install the view. For example, to not have the view installed when width = Any and height = Compact:

View installation

At first this looks like it will work. When you rotate the device to landscape the third view disappears as expected. Unfortunately when you rotate back to portrait the extra view shows up in the wrong spot:

Bad layout

The problem is that the stack view does not expect you to install and remove views in this way. It expects you to use its API (addArrangedSubview and removeArrangedSubview) so that it can automatically update constraints for the views it is managing.

A Better Approach - Hide the View

Luckily there is a much easier way. A stack view will automatically adjust the layout when you hide or unhide one of its views. So instead of using size classes in Interface Builder create an outlet for the view to our view controller.

@IBOutlet weak var extraHeart: UIImageView!

Then in the view controller we can use willTransitionToTraitCollection to test for the compact height and hide or unhide the view.

override func willTransitionToTraitCollection(newCollection: UITraitCollection,
  withTransitionCoordinator coordinator:
                            UIViewControllerTransitionCoordinator) {

  super.willTransitionToTraitCollection(newCollection, 
                            withTransitionCoordinator: coordinator)
  configureView(newCollection.verticalSizeClass)
}

The configureView method hides and unhides the view based on the vertical size class (the guard makes sure we do not try this before the system has set our outlet):

private func configureView(verticalSizeClass: UIUserInterfaceSizeClass) {
  guard extraHeart != nil else {
    return
  }
  extraHeart.hidden = (verticalSizeClass == .Compact)
}

The traitCollection property of the view controller gives us the size class to configure the view when we first load:

override func viewDidLoad() {
  super.viewDidLoad()
  configureView(traitCollection.verticalSizeClass)
}

That’s all you need to hide the view for compact heights:

Compact height

The updated sample code is in my Code Examples GitHub repository.

Further Reading

Never miss a post!

iOS Size Classes Cheat Sheet

Subscribe and get my free iOS Size Classes Cheat Sheet

Success! Now check your email to confirm your subscription and download your free guide to iOS Size Classes.

There was an error submitting your subscription. Please try again.

Unsubscribe at any time.
No time to watch WWDC videos?

Sign up to get my iOS posts direct to your inbox and I will send you a free PDF of my iOS Size Classes Cheat Sheet.

OK! Check your inbox (or spam folder) for an email to confirm your details and download your free guide to iOS Size Classes.

There was an error submitting your subscription. Please try again.

Unsubscribe at any time.
Archives Categories