This episode zooms in on constraints, priorities, and satisfiable layouts. For this episode, we revisit the project we created earlier in this series.
Constraint Priorities
Every constraint in a layout needs to have a priority. Let me show you what that means. Select the label, open the Size Inspector on the right to inspect the constraints of the label, and double click one of the constraints. This constraint has a priority of 1000. The value can range from 1 to 1000.
When you click the little triangle on the right, you can see three presets, Required (1000), High (750), and Low (250). If we set the priority to 999, you can see that the solid blue line turns into a dashed line. The dashed line indicates that the constraint is optional.
A constraint has a default priority of 1000 and that makes it a required constraint. Optional constraints have a priority that is less than 1000. Why is this useful? What is the benefit of required and optional constraints?
Optional and Required Constraints
At runtime, the Auto Layout engine needs to find a solution that satisfies every required constraint. That is important to remember. If the layout engine cannot accomplish that, the layout is unsatisfiable. Optional constraints are, well, optional. If the layout engine encounters an optional constraint, which it cannot satisfy, then it simply skips that constraint. If the same happens with a required constraint, then the layout engine needs to break the layout to satisfy the layout. It's also worth mentioning that the layout engine satisfies constraints in order of priority, from highest to lowest.
Let me show you how required and optional constraints can be helpful. Delete the label and the button, open the Object Library, and add a view to the view controller scene. Make the view as tall and as wide as the view of the view controller. Set the background to a bright green color and pin the view to the edges of the safe area layout guide. Make sure to uncheck Constraint to Margins. Later in this series, I explain what that option means. Don't worry about it for now.
Conflicting Constraints
This example confirms that every constraint has a priority of 1000 by default, making them required. But what happens if we add another constraint? Let's fix the width of the view to 350 points. Notice that three red lines appear. The leading constraint turned red, the trailing constraint turned red, and the constraint we added to fix the view's width also turned red.
The problem becomes clear when we click the red arrow in the top right of the Document Outline. Interface Builder shows us a list of conflicting constraints. Fortunately, it tries to help us. If we click the red octagon, Interface Builder shows us a window that lists the conflicting constraints and we are asked to select the constraints we wish to delete to resolve the conflict.
The layout engine discovered that it cannot satisfy the three required constraints at the same time and that makes sense. The superview is 375 points wide. We instruct the layout engine to pin the view to the leading and trailing edges of the safe area layout guide, and we require it to be exactly 350 points wide, which isn't possible.
Resolving Conflicts
We can resolve this issue by selecting the fixed width constraint, opening the Attributes Inspector on the right, and lowering the constraint's priority, for example, to 750. Notice that the solid line turns into a dashed line, indicating that the constraint is now optional. The Document Outline on the left also shows us the constraint's priority.
While this resolves the conflict, this isn't the solution we're looking for. The layout we want contains a green view that is 350 points wide or less, and that is centered in its superview. Let's start by making sure the view is 350 points wide or less. We can do this by selecting the fixed width constraint and setting its Relation to Less Than or Equal. As a result, the constraint is badged with a less than or equal to sign.
The next step is to make the constraint required by setting its priority to 1000. The error we encountered earlier pops up again, but that isn't a problem. To fix this issue, we open the Size Inspector and decrease the priorities of the leading and trailing constraints to 750, making them optional. To make sure the view is centered in its superview, we add another constraint. Open the Align menu at the bottom and center the view horizontally in its superview.
That looks much better. Let me give you a summary of the constraints we put into place. The view's width is constrained to 350 points or less, which is indicated by the solid line at the bottom. The solid line in the center shows us that the view is horizontally centered in its superview. The dashed lines are the optional leading and trailing constraints that pin the view to the leading and trailing edges of the safe area layout guide.
Build and Run
If we run the application in the iPhone SE simulator, you can see that the green view spans the entire area of its superview. The leading and trailing constraints take care of that. But what does the layout look like on a bigger screen, for example, the screen of an iPad Pro. That looks good too. The green view is centered horizontally in its superview. The view's width is 350 points and centered horizontally.
What I want you to take away from this episode is that every constraint has a priority. If the priority is equal to 1000, the constraint is required. If the priority is less than 1000, the constraint is optional.
If the Auto Layout engine cannot satisfy every required constraint, we end up with an unsatisfiable layout. If several required constraints conflict with one another, we end up with an ambiguous layout. The goal is to create a user interface with an unambiguous, satisfiable layout.