Adaptive Layout: Part 1 – Understanding the concepts

Since 2007 and the first generation of iPhone, with its 3.5-inch screen and 320×480 pixel resolution, Apple has continuously accelerated the release cycle of new devices and families of devices with different screen sizes, resolutions and pixel densities, and there is no sign of slowing down. The successive iOS versions followed along, but before iOS6 and the introduction of Auto Layout, the developers had to write many lines of code or use autoresizing masks and springs and struts in Interface Builder to support the various screen sizes and orientations. Fortunately, at the time there were fewer screen sizes to worry about, but the process was still tedious.

iOS8 marked another step forward in making the adaptive layout easier with the introduction of trait collections and size classes.

Views layout

Views are organized in a composition hierarchy. Each view is assimilated to a rectangular canvas with its own coordinate system in which the subviews have horizontal and vertical dimensions (width and height), and are drawn at the position defined by the origin point (their top left corner). The spatial attributes (origin and size) represent view’s frame in the superview’s coordinate system.

The screen is the virtual canvas where the views are drawn as successive layers, from the bottom of the hierarchy up. It represents the largest area that can contain visible elements; although not part of the views hierarchy iself, the screen is the top level component of this layered structure. How the views are laid out should primarily depend on the dimensions of the visible area. The goal of the adaptive layout is to make layout decisions based of the size of the screen.

Trait collections

The classes that conform to the UITraitEnvironment protocol give access to a set of dimensional properties that can be used to create a layout optimized for a specific configuration. These properties are stored in a UITraitCollection object:

  • displayScale
  • userInterfaceIdiom
  • horizontalSizeClass
  • verticalSizeClass

The UIKit classes that conform to the UITraitEnvironment protocol are UIScreen, UIWindow, UIViewController and UIView, which can be represented as a composition tree. The traitCollection property is inherited from the top level element (UIScreen) to the bottom level UIView, unless a subclass of these generic classes overrides the property.

class hierarchy conforming to UITraitEnvironment protocol

Size classes

From a layout standpoint, the horizontalSizeClass and verticalSizeClass properties are the most important because they define the available area where the subviews can be laid out. The type of these properties is UIUserInterfaceSizeClass, which is a simple enumeration declared as follows:

The horizontal and vertical dimensions of an object conforming to the UITraitEnvironment protocol don’t have absolute values (in points or pixels). Instead, the size classes express, in an abstract way, the relative amount of available space along the X and Y axis (compact means that there is a relatively small capacity and regular means there is more room for the content and it can be laid out in a way that optimizes the use of the additional space available).

Each screen size and orientation has its own default combination of size classes. Here is a comprehensive list for the Apple devices currently available. It’s worth noting that the larger dimension of the iPhone 6+ screen is assimilated to the regular size class (as for the iPad), while all the other iPhone models have compact size classes on both axis and orientations.

React to changes in the size classes

The adaptive UI design purpose is to be able to define a layout specific to the each trait collection (although the same layout can be used for multiple trait collections) and to automatically change the layout when the properties of the trait collection change.

The UITraitEnvironment protocol defines the -traitCollectionDidChange: method which can be implemented in UIViewController or UIView subclasses to adjust the layout depending on the new trait collection properties.

The problem with this method is that it doesn’t allow to detect changes in the device orientation (except for the iPhone 6+, which has different size classes for the two axis). And that’s precisely when we need to make changes in the content layout most of the time. Until the square screen device becomes a thing, what differentiates the portrait and landscape orientations is the size of the screen, meaning that the width and height are specific to each orientation.

The convenient UIViewController methods -willRotateToInterfaceOrientation:duration: and -didRotateFromInterfaceOrientation: are deprecated in iOS8. Fortunately, UIViewController and UIPresentationController conform to the new UIContentContainer protocol, which exposes the - viewWillTransitionToSize:withTransitionCoordinator: method allowing to detect screen width and height changes and react to them. More on how exactly use this method to adjust the content size and position with Auto Layout in the next blog post.

Conclusion

This is the first article in a series of blog posts about creating adaptive user interfaces using Auto Layout and the classes and protocols introduced in iOS8, which are intended to be more generic and simplify the support for the future Apple devices. It is an introduction to the size classes and trait collections, which are the base on which the adaptive layout can be built upon.

 

Catalin Rosioru

 

2 thoughts on “Adaptive Layout: Part 1 – Understanding the concepts

Comments are closed.