Getting to know Auto Layout
Like a slinky, the first few minutes with iOS’s springs and struts view layout system seems reasonable, but a few hours later your precious slinky is broken, and you’re filled with resentment and seething rage.
Perhaps for you it’s not quite that bad - for many developers it gets the job done - but it is certainly far from ideal. When you compare iOS to Android it becomes apparent how poor the layout system really is, especially if you have to design views for varying screen sizes and widths. And let’s be honest - it’s looking pretty likely that the next iPhone may well have a different aspect ratio.
Fortunately salvation is at hand, in the form of auto layout. Whilst new to iOS, auto layout was actually introduced to OS X last year. The Cocoa Touch implementation was announced by way of a ‘blink and you’ll miss it’ slide during Apple’s WWDC keynote, and since the technical implementation details are already public we can talk about its core concepts without fear of retribution from Apple’s legal department.
In many ways auto layout is to your views as ARC is to memory management. Like ARC it’s designed to make your life easier, but unless you want some nasty surprises down the line its best to understand a fair bit about the underlying concepts involved.
Springs and Struts
iOS, like OS X, uses a ‘springs and struts’ system. This term might be new to you, since in code these are referred to as autoresizing masks - properties such as
UIViewAutoresizingFlexibileRightMargin that determine how your view lays itself out in response to the superview changing its bounds.
Springs and struts is best described as ‘primitive’ - views are laid out relative to their superview, and you can’t express complex relationships between individual views. Springs allow views to expand and contract when their parent changes size, and struts define whether the views should have fixed or flexible margins. As we’ll see, the inability to dynamically resize views in response to their content can cause some big problems.
Fundamentally, auto layout lets views express relationships between themselves using equations. These are called constraints. A constraint takes the form
y = m*x + b, but it might be easier to think of them as commands such as “place me 50 points above this button”, or “no matter what my width make sure there’s a 20 point margin between me and the edge of the screen”.
There are a few things about constraints you should know - firstly, they can be inequalities - rather than
y = m*x + b' you could say 'y <= m*x+b. Constraints can also, unlike springs-and-struts, cross view hierarchies. However, the flexibility of constraints does introduce some problems. What happens if a view has two competing constraints, or if there aren’t enough constraints to determine what should happen when the view is resized? These are dealt with through priorities and ambiguous layout respectively.
It’s possible for a view to have competing constraints - perhaps a button has a constraint that determines its maximum width and a constraint that resizes the button to fit to its content. If the content width is greater than the maximum width value you’re going to have a problem.
Fortunately, you can indicate which constraint you’d like to ‘win out’ by assigning a priority value. Constraints are evaluated in order of their priority.
We’ve seen that constraints are fundamentally a series of equations that define the layout. For the layout to work, the equations must have a definite solution. An equation with multiple solutions could introduce ambiguous layout. For example,
x + y == 100 has a number of possible solutions (an infinite number, actually). We need to define either
y to solve the equation properly.
In auto layout such unsolvable equations introduce what’s called ambiguous layout.
Here’s a classic if slightly contrived problem with springs-and-struts - a simple dialog view with two buttons, “Quit” and “Save and Quit”. We lay our view out like so:
So you release your app, and it’s a big success - but you’re set on conquering the world. This means you’re going to have to translate your content into other languages, like German. Your German translator send back all your nicely translated localized strings, and you start integrating them back into the app. Unfortunately, there’s a problem - the German for “Save and Quit” doesn’t quite seem to fit:
Ouch. This happens a lot when localising applications: some languages (such as German) can be quite verbose, meaning your labels and buttons may frequently clip. How do we solve this? Well, until now we’ve had a few options:
- Localize our NIBs - but when we make an interface change we’ll have to update every single localised NIB.
- Code around it - if we haven’t used NIBs maybe we can come up with something in code. This is probably going to be quite unwieldy, and hard to maintain
- Do nothing - because nothing shows your international users you care like a broken layout
None of these are ideal. However, with auto layout we can have our cake and eat it - just plug in your localized strings file and that’s it (most of the time). We can tell the buttons to dynamically resize relative to each other, meaning we can be sure that the “Quit” button will be positioned nicely, and the “Save and Quit” button will vary its width to suit the content. The result is like so:
Autolayout can make internationalization easy. We’ve already seen how auto layout can resize interface elements in response to changing content sizes - but that’s really just the start. Many languages such as Arabic and Hebrew run right-to-left (‘RTL’), and supporting these frequently becomes an exercise in compromise. Ideally, your entire interface should really ‘flip’ itself, but this is easier said than done. Not so with auto layout - there’s in built support for RTL languages.
On the Mac, auto layout is also used to handle differing screen sizes, a problem that may well be rearing its head on iOS fairly soon. I’m looking forward to implementing auto layout in my own apps, and hopefully you will be too. It really is a huge step forward from the previous system.
If you’re interested in learning more about auto layout you can view Apple’s public documentation here. Registered developers will also have access to Apple’s WWDC 2012 session videos and associated documentation, which go into much more implementation detail about auto layout.
Image credit: Tangled Slinky image