Building Responsive User Interfaces in iOS6
You can use almost every iOS interface widget available, create multiple views and view controllers, add sounds and alerts, write files, and even manage application preferences, but until now, your applications have been missing a very important feature: responsive interfaces. The ability to create interfaces that display correctly regardless of your iDevice’s screen size or orientation is one of the key features that users expect in an application—and the key goal of responsive interface design.
This hour’s lesson explores the Xcode Auto Layout system and three different ways of adding rotatable and resizable interfaces to your apps. As you read this hour’s lesson, an important fact to keep in mind is that there are many different ways to solve the problem of responsive interface design. What works best for you may be entirely different than what I describe here.
Responsive Interfaces
Years ago, when I had my first Windows Mobile smartphone, I longed for an easy way to look at web content in landscape mode. There was a method for triggering a landscape view, but it was glitchy and cumbersome to use. The iPhone introduced the first consumer phone with on-the-fly interface rotation that feels natural and doesn’t get in the way of what you’re trying to do.
The iPhone 5 shakes things up by introducing the first 4” iPhone screen with a different aspect ration and resolution than the traditional 3.5” models. Does this mean that you need to worry about iPhone 3.5” displays, 4” displays, iPad displays, and portrait and landscape orientations for each? Nope! The iOS Auto Layout system makes it easy to adapt to different resolution displays and change your interface layout as your device resolution changes.
Although you should definitely plan to accommodate all sizes of the iPhone screen in your iPhone apps, the decision to handle rotation is entirely up to you. Consider how the user will be interfacing with the app. Does it make sense to force a portrait-only view? Should the view rotate to accommodate any of the possible orientations the phone may assume? The more flexibility you give users to adapt to their own preferred working style, the happier they’ll be. Best of all, enabling rotation is a simple process.
Enabling Interface Rotation
The projects that you’ve built to-date have had supported limited interface rotation because of a single line of code in a single method in your view controller. This is added by default when you use one of Apple’s iOS templates.
When an iOS device wants to check to see whether it should rotate your interface, it sends the supportedInterfaceOrientations message to your view controller. The implementation of supportedInterfaceOrientations just returns a value that describes the supported orientation. To cover more than one orientation, you just return the list of constants you want to use, separated by the | character.
There are seven screen orientation support constants, as listed here.
Orientation |
Orientation Support Constant |
Portrait |
UIInterfaceOrientationMaskPortrait |
Portrait upside-down |
UIInterfaceOrientationMaskPortraitUpsideDown |
Landscape left |
UIInterfaceOrientationMaskLandscapeLeft |
Landscape right |
UIInterfaceOrientationMaskLandscapeRight |
Any Landscape |
UIInterfaceOrientationMaskLandscape |
Anything but upside-down |
UIInterfaceOrientationMaskAllButUpsideDown |
Anything |
UIInterfaceOrientationMaskAll |
For example, to allow your interface to rotate to either the portrait or landscape left orientations, you implement supportedInterfaceOrientations in your view controller with the code in Listing 16.1.
Listing 16.1. This Method Activates Interface Rotation
- (NSUInteger
)supportedInterfaceOrientations {return
UIInterfaceOrientationMaskPortrait
|UIInterfaceOrientationMaskLandscapeLeft
; }
The return statement handles everything. It returns the combination of the two constants that describe landscape left and portrait orientations.
At this point, take a few minutes and go back to some of the earlier hours and modify this method in your view controller code to allow for different orientations. Test the applications in the iOS simulator or on your device. For iPhone apps, try switching between 3.5” and 4” displays.
Some of the applications will probably look just fine, but you’ll notice that others, well, don’t quite “work” in the different screen orientations and sizes, as shown in Figure 16.1 (ImageHop, from Hour 8, “Handling Images, Animation, Sliders, and Steppers”).
Figure 16.1. Enabling an orientation doesn’t mean it will look good.
Everything we’ve been building has defaulted to a portrait design and, for the iPhone, a 4” screen, so how can we create interfaces that look good regardless of the orientation and size of the screen? We obviously need to make some tweaks.
Designing Rotatable and Resizable Interfaces
In the remainder of this hour, we explore several different techniques for building interfaces that rotate and resize themselves appropriately depending on the device, or when the user changes the device’s screen orientation. Before we get started, let’s quickly review the different approaches and when you’d want to use them.
Auto Layout
The Xcode Interface Builder (IB) editor provides tools for describing how your interface should react when it is rotated or when the size of the screen can be variable. It is possible to define a single view in IB that positions and sizes itself appropriately—no matter what the situation—without writing a single line of code. This bit of Apple magic is called Auto Layout. It will be your best friend and worst enemy in creating responsive interfaces.
Using Auto Layout should be the starting point for all interfaces. If you can successfully define portrait and landscape modes in a single view in the IB editor, your work is done.
Unfortunately, Auto Layout doesn’t work well when there are many irregularly positioned interface elements. A single row of buttons? No problem. Half a dozen fields, switches, and images all mixed together? Probably not going to work.
Programming Interfaces
As you’ve learned, each UI element is defined by a rectangular area on the screen: its frame property. If we programmatically define an application interface, we can make it into anything we want. Although this might sound challenging, it’s actually very simple and very effective for creating interfaces that vary dramatically between different sizes and orientations.
For example, to detect when the interface rotates, we can implement the method didRotate-FromInterfaceOrientation in our view controller. The view controller property interface Orientation will tell us the current orientation of the interface, by containing one of these four constants:
Orientation |
Current Orientation Constant |
Portrait |
UIInterfaceOrientationPortrait |
Portrait upside-down |
UIInterfaceOrientationPortraitUpsideDown |
Landscape left |
UIInterfaceOrientationLandscapeLeft |
Landscape right |
UIInterfaceOrientationLandscapeRight |
The drawback to doing everything in code is that you are doing everything in code. It becomes very difficult to prototype interface changes and visualize what your final interface will look like. In addition, it is harder to adapt to changes in the future. It’s best, in my opinion, to use a combination of Auto Layout with hand-coded interfaces to provide the best flexibility and speed of development.
Swapping Views
A more dramatic approach to changing your view to accommodate different screen orientations is to use entirely different views for landscape and portrait layouts. When the user rotates the device, the current view is replaced by another view that is laid out properly for the orientation.
This means that you can define two views in a single scene that look exactly the way you want, but it also means that you must keep track of separate IBOutlets for each view. Although it is certainly possible for elements in the views to invoke the same IBActions, they cannot share the same outlets, so you’ll potentially need to keep track of twice as many UI widgets within a single view controller.