Dissecting Auto Layout Constraints

Dissecting Auto Layout Constraints

If you plan to build an iOS application that look great on any device, then Auto Layout is your only viable option. The user interface of modern iOS applications is driven by Auto Layout and Apple continues to improve and invest in Auto Layout with every iteration of the platform.

Constraints are the building blocks of user interfaces powered by Auto Layout. In this tutorial, I would like to zoom in on the anatomy of constraints. By understanding the properties and limitations of constraints, you get a better grasp of how Auto Layout works under the hood.

Constraints Describe Relationships

The first thing you need to know about constraints is that each constraint describes the relationship between items in the view hierarchy. An item can be a view or a layout guide.

Each constraint can be translated into a linear equation. That linear equation is used by the Auto Layout engine to calculate the frames of the views in the view hierarchy. The layout engine inspects the constraints and attempts to find a solution, that is, a layout that fits the constraints.

If the layout engine finds multiple solutions, the layout is ambiguous. If the layout engine is unable to find a solution that satisfies every required constraint, the layout is unsatisfiable. The goal of the layout engine is finding a layout that is unambiguous and satisfiable.

Constraint Blueprint

The basic blueprint of a constraint looks something like this. But what are items and attributes? And what is the difference between multiplier and constant?

item1.attribute1 = multiplier x item2.attribute2 + constant

Items

As I mentioned earlier, a constraint describes the relationship between two items in the view hierarchy. Items can be views or layout guides. An example better illustrates this. In the example below, the constraint describes the relationship between a label, item 1, and its superview, item 2.

label.top = 1.0 x superview.top + 8.0

In the next example, the superview is replaced by the top layout guide, a read-only property of the view controller that defines the highest vertical position visible to the user.

label.top = 1.0 x topLayoutGuide.bottom + 8.0

It is possible to omit the second item as shown in the example below. The constraint defines that the width of the label, item 1, is equal to 200.0 points. Because the second item is absent, the attribute is set to NotAnAttribute.

label.width = 1.0 x NotAnAttribute + 200.0

But what are attributes?

Attributes

The attributes in a constraint reference the attributes of the items that need to be constrained. There are two types of attributes:

  • size attributes (width and height)
  • location attributes (top, bottom, leading, trailing, ...)

Let us revisit the previous examples. In the first example, the top attribute of the label and the top attribute of the superview are constrained. The constraint defines that the top edge of the label needs to be positioned 8.0 points from the top edge of its superview.

label.top = 1.0 x superview.top + 8.0

The second example is very similar. The top attribute of the label and the bottom attribute of the top layout guide are constrained.

label.top = 1.0 x topLayoutGuide.bottom + 8.0

The constraint of the third example constrains the width attribute of the label to 200.0 points. Because the constraint doesn't contain a second item, the attribute is replaced by a placeholder value, NotAnAttribute.

label.width = 1.0 x NotAnAttribute + 200.0

Relationship

Earlier, I mentioned that a constraint describes a relationship. The relationship doesn't always have to be an equality, though. There are three types of relationships:

  • = equal to
  • <= less than or equal to
  • >= greater than or equal to

This is very useful to create flexible and dynamic layouts. The following example illustrates this. In the example, we assign two constraints to the same label. Even though both constraints describe the width of the label, they are not conflicting.

label.width >= 1.0 x NotAnAttribute + 200.0
label.width <= 1.0 x NotAnAttribute + 400.0

Together the constraints define that the label's width needs to be greater than or equal to 200.0 points and less than or equal to 400.0 points. This example shows that multiple constraints can constrain the same attribute of an item.

Multipliers & Constants

The multiplier is the value the attribute of the second items is multiplied by. This is useful if a view needs to have a particular aspect ratio as shown below.

Constraint Multiplier

The constant is the value added to the attribute of the second item. As we saw earlier, this is useful for positioning views in a view hierarchy or for defining the size of a view.

Constraint Constant

Constraint Priorities

Every constraint has a priority, a value between 1 and 1000. If the priority of a constraint is equal to 1000, the constraint is required. This means that the layout engine must satisfy the constraint to end up with a satisfiable layout.

Constraints with a priority less than 1000 are optional constraints. The layout engine attempts to satisfy optional constraints, but it skips an optional constraint if it prevents the layout engine from finding an unambiguous, satisfiable layout.

In a future tutorial, I discuss required and optional constraints in much more detail. While the concept is simple at first glance, there is quite a bit more to it.

What's Next?

Questions? Leave them in the comments below or reach out to me on Twitter.