Categories
Uncategorized

Overriding traits with embedded UINavigationController

In Rigelian the album view comes in 2 flavours: a wide display for the iPad, and a narrow version for the iPhone. The view controller is based on a single nib file, with constraints specific for the horizontal size classes .regular and .compact.

View for regular horizontal size class
View for compact horizontal size class

While implementing a 3-column layout for artists, it turned out that the remaining space for the album view becomes too narrow for the wide display, resulting in many song titles being shortened. So I want to show the narrow version of the screen, like shown here:

But the UINavigationController and its child controllers report the horizontal size class as .regular, regardless of how wide it actually is (probably assuming a UINavigationController always gets the full screen), so be default the wide display is used like this:

Turns out this showing the compact view can be easily achieved by overwriting the horizontalSizeClass, and that no changes are needed to nib file. By doing this in the willShow delegate for the UINavigationController, every presented view will have the correct traits.

func navigationController(_ nc: UINavigationController, 
                          willShow viewController: UIViewController,
                          animated: Bool) {
  // Use compact view whenever the width is below 600
  let size: UIUserInterfaceSizeClass = nc.view.frame.size.width < 600 
                                          ? .compact : .regular
  let overrideTraitCollection = UITraitCollection(horizontalSizeClass: size)

  nc.setOverrideTraitCollection(overrideTraitCollection,
                                forChild: viewController)
}

I noticed that in the presented UIViewController, the override is not yet visible in viewWillAppear, and that it is visible in viewDidAppear.