With ever more devices and new multitasking features supported by iOS, it’s important to create user interfaces that scale gracefully to different screen sizes. Size classes are the most effective tool for tackling this problem. In this post, we’ll look at what size classes are and how to use them.
Size classes become even more useful when combined with auto layout. If you’re unfamiliar with this system, check out my earlier posts on how to use auto layout in theory and in practice. We’ll be looking at how the two systems work together in this post.
A New Way of Thinking
Before size classes, iOS developers would think carefully about each device and orientation they wanted to support. With size classes, those specific concerns are replaced with a more generalized set of ideas.
Instead of worrying about user interface idiom and orientation, we think only about our interface’s approximate size. Let’s take a look at how to visualize this:
With size classes, our interface always fits into one of two categories: regular or compact. This concept applies in both the horizontal and vertical directions.
Breakdown by Device and Orientation
Here’s a handy chart of size classes by device and orientation:
|iPhone (5.5 inch)||Compact width,
|All Other iPhones||Compact width,
There are some interesting quirks here. iPad does not have a 1:1 aspect ratio, but its size class is always ‘regular’. Also, iPhones other than the 5.5″ models always have a ‘compact’ width, regardless of orientation.
Implementing Size Classes in Interface Builder
From within Interface Builder, we can create different versions of our interface, one per size class. To start, open the size class menu by clicking the button at the bottom of the window that reads ‘w Any h Any’.
The 3×3 grid on this menu describes all the possible permutations of horizontal / vertical and compact / regular size classes. It includes several settings that allow us to select ‘any’, which includes both ‘compact’ and ‘regular’.
The size class menu can be confusing at first. Think of the blue area as a representation of the size of our interface. The interface always starts in the upper left, so the farther down and to the right we go, the bigger the size class.
Clicking on the grid selects which version of our interface we’re editing. Any changes made within one version of our interface stay within only that version, so pay careful attention to the size class settings when making changes.
When switching between size classes, we can think of the ‘any’ setting as being our default. More specific settings, i.e. ‘regular’ or ‘compact’, will override those defaults.
Let’s look at an example of how to use auto layout with size classes:
When examining any object in the Identity Inspector, we see a section at the bottom that allows us to manipulate its size classes. We can specify multiple size classes in this list. Any time the interface’s size class matches one of the classes in that list, the object will be ‘installed’, i.e. added to our interface.
Using this technique with our NSLayoutConstraint objects allows us to create a totally different layout for each size class. Similarly, using the technique on our UIView objects allows us to create totally different view hierarchies.
When switching between size classes, we can notice some of the icons in the Document Outline look faded. These faded icons signify that the item is in our document, but will not be installed for the current size class.
There are a lot of moving parts here. We can have a different view hierarchy and layout for several size classes. It’s hard to hold all that information in our heads. To relieve some of that cognitive burden, we can preview our interface using the Assistant Editor. Open this editor with the button at the upper right of the Xcode window that looks like a Venn diagram.
Use the Jump Bar to select ‘Preview’. In this preview tool, we can simultaneously see our interface on multiple devices with different size classes. We can also change the user interface orientation on our preview devices.
Implementing Size Classes in Code
When approaching size classes using only code, we’ll need to use the UITraitCollection class. This class encapsulates all size class information as well as a few other things that will not be covered here.
Many of the classes that we use all the time in iOS development, including UIView and UIViewController implement a protocol called UITraitEnvironment. These trait environment classes allow us easy access to instances of UITraitCollection. We can access it using the traitCollection property.
Let’s look at an example of a UIViewController subclass that gets a callback when the size class changes:
When using the traitCollectionDidChange method, we can manage the insertion and removal of NSLayoutConstraint and UIView objects. This allows us to implement the same behavior as the ‘installed’ checkboxes in Interface Builder.
That’s all for now. I hope this post has armed you with enough knowledge of size classes to make your interfaces more robust and flexible across all iOS devices.