Auto Layout Concepts

The fundamental building block in Auto Layout is the constraint. Constraints express rules for the layout of elements in your interface; for example, you can create a constraint that specifies an element’s width, or its horizontal distance from another element. You add and remove constraints, or change the properties of constraints, to affect the layout of your interface.

When calculating the runtime positions of elements in a user interface, the Auto Layout system considers all constraints at the same time, and sets positions in such a way that best satisfies all of the constraints.

Constraint Basics

You can think of a constraint as a mathematical representation of a human-expressable statement. If you’re defining the position of a button, for example, you might want to say “the left edge should be 20 points from the left edge of its containing view.” More formally, this translates to button.left = (container.left + 20), which in turn is an expression of the form y = m*x + b, where:

An attribute is one of left, right, top, bottom, leading, trailing, width, height, centerX, centerY, and baseline.

The attributes leading and trailing are the same as left and right for left-to-right languages such as English, but in a right-to-left environment such as Hebrew or Arabic, leading and trailing are the same as right and left. When you create constraints, leading and trailing are the default values. You should usually use leading and trailing to make sure your interface is laid out appropriately in all languages, unless you’re making constraints that should remain the same regardless of language (such as the order of master and detail panes in a split view).

Constraints can have other properties set:

Constraints are cumulative, and do not override each other. If you have an existing constraint, setting another constraint of the same type does not override the previous one. For example, setting a second width constraint for a view does not remove or alter the first width constraint—you need to remove the first constraint manually.

Constraints can, with some restrictions, cross the view hierarchy. In the Mail app in OS X, for example, by default the Delete button in the toolbar lines up with the message table; in Desktop Preferences, the checkboxes at the bottom of the window align with the split view pane they operate on.

You cannot set a constraint to cross the view hierarchy if the hierarchy includes a view that sets the frames of subviews manually in a custom implementation for the layoutSubviews method on UIView (or the layout method on NSView). It’s also not possible to cross any views that have a bounds transform (such as a scroll view). You can think of such views as barriers—there’s an inside world and an outside world, but the inside cannot be connected to the outside by constraints.

Intrinsic Content Size

Leaf-level views such as buttons typically know more about what size they should be than does the code that is positioning them. This is communicated through the intrinsic content size, which tells the layout system that a view contains some content that it doesn’t natively understand, and indicates how large that content is, intrinsically.

For elements such as text labels, you should typically set the element to be its intrinsic size (select Editor > Size To Fit Content). This means that the element will grow and shrink appropriately with different content for different languages.

Application Architecture

The Auto Layout architecture distributes responsibility for layout between controllers and views. Rather than writing an omniscient controller that calculates where views need to go for a given geometry, views become more self-organizing. This approach reduces the complexity of controller logic, and makes it easier to redesign views without requiring corresponding changes to the layout code.

You may still want a controller object that adds, removes, or adjusts constraints at runtime. To learn more about managing constraints in code, read “Working with Auto Layout Programmatically.”

The Role of the Controller

Although a view specifies its intrinsic content size, the user of the view says how important it is. For example, by default, a button:

  • Strongly wants to hug its content in the vertical direction (buttons really ought to be their natural height)

  • Weakly hugs its content horizontally (extra side padding between the title and the edge of the bezel is acceptable)

  • Strongly resists compressing or clipping content in both directions

In a user interface containing two buttons next to each other, for example, it’s up to the controller to decide how the buttons should grow if there’s extra room. Should just one of the buttons grow? Should both grow equally? Or maybe proportionally to each other? If there isn’t enough room to fit both buttons without compressing or clipping the content, should one button be truncated first? Or both equally? And so on.

You set the hugging and compression priorities for a UIView instance using setContentHuggingPriority:forAxis: and setContentCompressionResistancePriority:forAxis: (for NSView, you use setContentHuggingPriority:forOrientation: and setContentCompressionResistancePriority:forAxis:). By default, all UIKit- and AppKit-supplied views have a value of either NSLayoutPriorityDefaultHigh or NSLayoutPriorityDefaultLow.