iOS8 introduced size classes that allowed for the UI in an app to adapt to different devices and orientation. iOS 8 also introduced UITraitCollection, including two new properties, horizontalSizeClass, and verticalSizeClass. The UIUserInterfaceSizeClass represents the relative size available for an app in either the horizontal or vertical dimension. The size class values are defined as Compact, Regular or Unspecified.

Some developers may not have been compelled to reconfigure old xibs or storyboards using size classes without seeing a need. With multi-tasking being introduced for iOS 9, Apple is strongly suggesting that apps use size classes. If an app is already using size classes, little needs to be done to prepare for multi-tasking.

Size Classes in iOS 8

Current Apple devices have the following size classes when a view controller fills the entire screen:

Item Horizontal Size Class Vertical Size Class
iPad Regular Regular
iPhone(Portrait) Compact Regular
iPhone(Landscape) Compact Compact
iPhone6+(Landscape) Regular Compact

There are times when your view controller does not take up the entire screen however, so it needs to know how to adapt the UI based on the size. A good example of this is the UISplitViewController, where, on an iPad, the main view controller is in Compact width, Regular Height and the detail view controller is in Regular, Regular.

Any is used to encompass both Compact or Regular. Use Any when you want the same views or constraints for different size classes.

Working With Size Classes

Getting our hands dirty at this point you can download the sample project at GitHub. Opening the storyboard you will find a yellow view containing a textField that is horizontally stretchy and a single button.

At the bottom of the storyboard is the size class selector which by default is in

Click on the size selector to see the different options available.

Here there are nine different options for each of the Compact, Any, Regular size combinations. More specific combinations will override base Any values. For example, a Regular-Regular layout would be more specific than a Regular-Any.

In the sample project, the text field in the yellow view in regular width might not need to be that large so there is room to add other views. For the sample, we are going to add an additional label and button.

First, choose the wRegular-hAny size layout. To add more views to the right of Button1, its trailing contraint must be removed. Find the trailing constraint for Button 1 and in the Attributes Inspector click on the + by the Installed.

Choose Regular Width | Any Height. Unselect the wR hAny so that constraint will only be added to other size layouts.

While in the wRegular hAny layout the constraint is no longer highlighted in the Document Outline

and we have warnings for misplaced views which will be addressed by adding the new views in place.

There are several ways create the extra room on the right side of Button1. One way to solve that issue without disconnecting current constraints is to create a temporary constraint to replace the one that was just removed. Select Button1 and create a trailing constraint. Change its constant from 31 to 200. Notice in the attributes inspector that constraint is only being used for wR hAny. Delete the temporary constraint once you are happy with the spacing.

Add a label and another button to the right of Button1. Add height, width, vertical center, and leading-trailing constraints. The leading-trailing constants are not that important. Just make them look nice. The right side of the yellow view should now look similar to:

To preview what the view will look like on different layouts open the Assistant Editor by selecting Cmd-Opt-Return. Select Automatic or Manual to show a drop down menu and choose Preview. By default, this displays the view on an iPhone 4-inch. Select the + at the bottom left of the Assistant Editor to see other previews.

No coding and the sample project has a different look for different layouts. However, at some point, the Label or Button2 might need to be referenced in the code. They do not exist in Compact width which could lead to trouble.

Create a reference outlet to Button2 in your code:

@IBOutlet weak var button2: UIButton!

The forced optional for button2 here will cause a crash when the xib is layedOut for a compact width. This outlet must be changed to an optional.

@IBOutlet weak var button2: UIButton?

Later in the code the optional button2 should be checked before using:

button2?.setTitle("Go", forState: .Normal)

If additional work is needed for the regular width you could check the traitCollection first and then use a forced optional.

if(self.traitCollection.horizontalSizeClass == .Regular){
 button2!.setTitle("Go", forState: .Normal)
 //additional work for Regular size
}

Closing

Making use of Size Classes within StoryBoard or a .xib file makes it easy for developers to create Adaptive UI for different devices. Feel free to explore iOS tutorials at the CapTech blog. If you have questions you may contact me at estroh@captechconsulting.com.