fbpx

Blogs from the Ranch

< Back to Our Blog

iOS Auto Layout: Fun Facts and Tips

Avatar

Joe Conway

Editor’s note: This post originally appeared on the the blog of Joe Conway, co-author of iOS Programming:The Big Nerd Ranch Guide.

Have you ever stared at the tracking information for your new MacBook, hitting refresh every five minutes? It is infuriating. But the fact that a MacBook can come off the assembly line somewhere in China and end up at my doorstep a few days later is a serious work of mathematical art.

Consider all of the issues in optimizing the pickup and delivery of your next MacBook: a company like FedEx has to factor in the number of trucks they have, the amount of goods that can fit on those trucks, the cost of gas, the distance from their nearest distribution center to your doorstep and so on. If they were to just shoot from the hip and deliver things in whatever order their manager thinks is best, they would run out of money or your shiny laptop wouldn’t show up. Instead, they have to rely on a field of math called linear programming to determine the way they operate.

Linear programming (which has nothing to do at all with programming in the way we think of it, but instead, is a synonym for linear optimization for math folks) is used to solve equations for which there are a lot of variables that depend on each other. FedEx needs to minimize some of these variables (like the amount they spend on gas) and maximize some others (like how many items can be delivered in a day).

Because there are so many variables involved and each of their ranges is so vast, a human being couldn’t find the optimum value for each of the variables to minimize their costs and maximize their production, but a linear objective function can. A human being can set up some constraints for each variable, like a truck can travel up to 200 miles in a day and gas costs $3.50 today. Each of these constraints is a simple linear equation, like travel < = 200.0 and gas = 3.50. A linear objective function is a combination of all of these equations solved at once that finds the optimum value for each unsolved variable.

What does this have to do with autolayout? The autolayout system is one big linear objective function. Each NSLayoutConstraint you create is just one linear equation in a linear objective function. For example, one constraint could be view.left = anotherView.right + 10 and another could be view.width >= 20.

When a view is being laid out, the linear objective function is evaluated to determine a minimum and maximum value for each part of a view’s frame. A valid set of constraints for autolayout is when every variable has a maximum equal to its minimum; that is, there is only one solution to satisfy every constraint in a view hierarchy. (If there is more than one solution to the function, you have an ambiguous layout, if there isn’t a solution, you have conflicting constraints and you get an exception.)

Because of the way linear objective functions are evaluated, there isn’t an order that the constraints are computed in. So if that was how you were approaching constraints, get that out of your head: an equation like view.top = anotherView.bottom + 10 doesn’t mean that you find the value of anotherView’s bottom first and add 10 to get view’s top. It is just one more equation that has to be satisfied for your layout to work; both of these variables can change depending on the other constraints.

Of course, the math behind all of this is really complicated. The implementation of autolayout is less complicated, but let’s not pretend it is easy at first. So, here is what I recommend:

Use autolayout only when you need to

Autoresizing masks aren’t deprecated or obsolete. Just like Core Data didn’t make archiving obsolete nor did blocks make delegation useless, you will still use autoresizing masks. Many iOS applications—while they may have pretty artwork—are pretty simple, layout-wise. You have a table, it has some cells, there is some stuff in the cells, there are some buttons above it and maybe a duck. Well, probably not a duck, but do you really need autolayout to keep the table view on the bottom of the screen and the buttons as a header on top? Does a cell with two text fields need autolayout to keep them aligned with each other? Will rotating the device, putting into a navigation controller or running it on an iPhone 5 really change the layout of this view? No. So don’t overkill it with autolayout.

The keyboard shortcut you need to know about

Manipulating the layout of a user interface in an XIB is, let’s face it, a cruel joke. Once a view is dropped into an XIB, you get all kinds of constraints that make sense for the position of that view where you dropped it—but not where you eventually want it. On top of that, Xcode enforces the constraints that apply to your views when manipulating them in the XIB—got a label that is pinned to match the size of the button below it? Xcode may not let you drag the resizing controls for that label.

Unless you hold the command key. The most useful but under-documented feature of autolayout is holding the command key while manipulating views in an XIB file. While holding the command key, Xcode lets you break any constraint applied to a view while resizing it.

Stop thinking about frames

When laying out an interface, we typically think about the frame of a view. Stop. The frame of a view is an absolute position and size. That doesn’t make sense when a view should lay itself out relative to the rest of the screen. Want to think about the size of a view? Think about its intrinsic content size. Want to think about the position of a view? Think about its offset from other views in the interface. A button doesn’t have a frame of {20, 40, 200, 40}, no, it is 10 points below a label, centered on the Y axis of its superview and wants to fit its title comfortably.

Change constants, not constraints

One of the more useful (and difficult) features of autolayout is the ability to make dynamic user interfaces. If your model changes and a new button needs to move into place, don’t delete the current constraint and create a new one. Finding constraints at runtime is not straightforward, but modifying the constant of a constraint is very simple. If a button needs to slide in from the right side of the screen, create a constraint where initially button.left = superview.left + 400. When it comes time to slide it in, change the constant so that the equation is button.left = superview.left + 200. As an added bonus, animation comes for free:

    [[self buttonEdgeConstraint] setConstant:200];
    [UIView animateWithDuration:0.5 animations:^{
    [[self button] layoutIfNeeded];
    }];

Understand the limitations and bugs

Right now, setting up constraints in an XIB file for a UITableViewCell doesn’t do what you expect it to do: each constraint thinks that the superview is the instance of UITableViewCell, not the cell’s contentView. This means that you will never get what you expect. Instead, turn off autolayout for a UITableViewCell XIB and either set up constraints programmatically or use autoresizing masks.

When modifying an XIB, Xcode won’t let you set up constraints that are invalid (for the most part). That means if you have a constraint you don’t want, you may have to add another constraint before you can delete it.

The thickness of the constraint line in the XIB is your key: a thin blue line is a required constraint, whereas the thicker blue line is a user constraint. Required constraints can’t be deleted, otherwise the layout would become invalid. When a set of constraints over-qualifies a view’s frame, the constraints that aren’t necessary automatically become user constraints that can be deleted. For example, if you plop a text field onto the screen, it may set up a left and right edge constraint. If you don’t want the right edge constraint, pin the width of the text field—this makes the right edge and width constraints redundant. Then you can delete the right edge constraint and the width constraint will become required.

Avatar

Joe Conway

Not Happy with Your Current App, or Digital Product?

Submit your event

Let's Discuss Your Project

Let's Discuss Your Project