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.
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:
xare attributes of views.
bare floating point values.
An attribute is one of
trailing are the same as
right for left-to-right languages such as English, but in a right-to-left environment such as Hebrew or Arabic,
trailing are the same as
left. When you create constraints,
trailing are the default values. You should usually use
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:
Constant value. The physical size or offset, in points, of the constraint.
Relation. Auto Layout supports more than just constant values for view attributes; you can use relations and inequalities such as greater-than-or-equal to specify, for example, that a view’s
width >= 20, or even that
textview.leading >= (superview.leading + 20).
Priority level. Constraints have a priority level. Constraints with higher priority levels are satisfied before constraints with lower priority levels. The default priority level is required (
NSLayoutPriorityRequired), which means that the constraint must be satisfied exactly. The layout system gets as close as it can to satisfying an optional constraint, even if it cannot completely achieve it.
Priority levels allow you to express useful conditional behavior. For example, they are used to express that some controls should always be sized to fit their contents, unless something more important should take precedence. For more information about priority levels, see
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.
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
NSView, you use
setContentCompressionResistancePriority:forAxis:). By default, all UIKit- and AppKit-supplied views have a value of either