In this chapter we’ll learn how to incorporate a very powerful development component - Auto Layout.
The essence of Auto Layout comes to specifying relative layout conditions and let Swift deal with particular circumstances for us by applying those conditions.
Setting the goal
Let's remind ourselves of how our current implementation behaves:
And what we are aiming for here (the last one will need some special attention, but the idea is the same):
To layout UI elements using Auto Layout we need to learn its key component - Constraints.
Constraints, in the layout context are layout rules that specify a parameter of a view (i.e. width, height) or relationship between two views (i.e. centre of one view to centre of another). Autolayout implements a set of constraints that allows to 'automatically' position and size all the views considering the screen size and orientation.
A constraints defines a distance in points (pt) that must remain constant.
For example, if constrain height of a button to 44pt, it will remain 44pt tall no matter what device or orientation it's presented on.
Or, if we constrain distance for a button from the bottom of the screen to 20pt, it will alway remain at the 20pt from the bottom of the screen.
Defining a complete set of constraints
If we left our button at that, there would be a major confusion with our intensions - we've said we want it 44pt tall and 20pt from the bottom of a containing view (the main view of the screen in our example).
There's an array of variations how we can satisfy those rules and still have space left for improvisation:
We basically only specified vertical parameters. Ant got some questions to answer here:
What should be the width - constant or stretched?
What's the horizontal arrangement?
Should the view stay in the centre? or shift to the left or right? by how much? from the centre or relative to the edges of the containing view?
As you can see, there's plenty of uncertainty here. In order to render a view correct, we must (somehow) know 4 components - position(x, y) and size(with, height). Remember frames? - those are the parameters of a frame, once those are clear, we can certainly position and size a view.
So, why somehow?
There are different ways how we can either specify those parameters directly or derive them from other information we have.
For example, if we state that our button must remain 30pt from the left and right edges of a containing view, its width can be calculated as
width of the containing view - 30x2 .
Or, if a button needs to keep 40pt distance from a sibling view above it, its y positioning can be calculated as
y + height of a sibling view + 40 .
Another example of defining 2 constraints:
Button1 needs to keep 40pt distance from View1
Button1 needs to keep 40pt distance from View2
Will result into Autolayout staying to calculate y for Button1 twice:
Button1->y (y1) = View1->y + View1->height.
Button1->y (y2) = View2->y + View2->height.
See the trouble coming? :waw:
You guessed it right - if the calculations generate results when y1 is not equal y2 ( y1 != ;) y2) we get ... Conflict!
I'll let you on a secret, Rule #2 can be flexed a little. :soleil:
Let's follow the rules for the moment!
Variations of constraints
Let's explore ways we can set the necessary parameters.
Setting the size (width, height):
by specifying width/height.
by specifying width and height relative to a sibling view or the containing view.
Setting distance from one of the edges of a view (left, right, top, bottom) to one of the edges of other sibling views or edges of containing view.
Relate center of a view to:
the center of a sibling view or containing view with an offset (offset 0 means the renters will be in the same point)
edges of other sibling views or the containing view.
Auto Layout vs. Frame
If Auto Layout requires the very same parameters defined (x, y, width, height), what's the difference?
By using frame parameters directly we set those values forever. Regardless a device or orientation the size and position of views will remain the same. We already saw the complication of that when tested our screen designed for iPhone 8 portrait producing inadequate appearances for other screen sizes and orientations.
Auto Layout constraints, on the other hand, provide relative definitions, so that they can be adjusted as circumstances change and always produce intended layout. For example, we can still constrain width to a fix dimension, and, in addition request it to be entered horizontally on the screen - so it will always appear centered horizontally for all device sizes and orientation. When utilizing frame directly would display it at the same distance from the left following the original x value.
So, we have our frame values configured in storyboard. And, we can define constraints for Auto Layout.
What about Rule #2? Should this result into a conflict?
This's alright, if Auto Layout is used, the manual frame settings (set in storyboard or programmatically) are simply ignored.
Auto Layout & Safe area
How's Auto Layout altercated by Safe area?
Auto Layout and Safe are are independent of each other. It's our responsibility to consider the safe area when creating constraints.
Xcode offers help as usual - safe area guides!
Let's go ahead and make sure we've got both Auto Layout and Safe area guides enabled. In storyboard, select View Controller, switch to the 'File Inspector' on Utilities panel and make sure related checkboxes are checked off:
Let's constrain our views!
In the bottom right of the central area in storyboard you can see icons we haven't reviewed yet - those are to control constraints:
Here's what we need to accomplish:
Title Image - fixed width and height, center horizontally, position vertically at the top of Safe area.
Creation Frame - fixed width and height, center horizontally, position vertically following Title Image.
Creation Image Container - snap to edges of Creation Frame with a frame width offset.
Creation Image - snap to edges of Creation Image Container (no gap).
Startover Button - fixed width and height, center to the bottom right corner of Creation Frame.
Color Label - align left and right edges to the left and right edges to Creation Frame, fixed height, position vertically following Creation Frame.
Color Swatch Container - fixed width and height, center horizontally, position vertically following Color Label.
Color Swatches - let them be. ;)
Share Button - match width to the width of Creation Frame, fixed height, center horizontally, position at designed distance from the bottom of safe area.
Unicorn ... just kidding, we'll leave the Unicorn be. :p
What Unicorn? :waw:
Whether you've already completed the Unicorn activity at the end of previous chapter, you may choose to apply autolayout to the activity functionality, however it's not required.
First'e make sure we currently have all the elements within the Safe area. Select the Safe area item on the storyboard navigation and observe the highlighted area on our screen:
1. Title Image
Select Title image and click 'Add new constraints' icon.
We have options here to contain distance to the closets 'neighbor' on the top, bottom, left and right.
Enable the top constraints - we are starting at the very top of Safe area. We can also fix width and height in this popup - check those off and click 'Add 3 constraints':
Right after we've closed the popup, we can observe changed in our storyboard navigation:
Here's what's new:
Two constraints - width and height - added under the title image.
One constraint - distance from the top - added under the main view.
And, an arrow in a red circle in the right top corner, which looks alarming. :colere:
Click on the red circle with an arrow and you'll see that some constraints are missing.
Well, remember, rule #1 requires 4 values defined and we've defined only 3, horizontal positioning is still a mystery - we need to center it. This time click on 'Align' icon and check of horizontal alignment (keep the number 0 - this is an offset we could specify should we need a new shifted left or right of the center):
And let's take a look at the storyboard navigation again:
This time we have a few more changes:
One more constraint added to the main view indicating entering to the view.
The red arrow's GONE! :zorro:
And we've got nice blue lines surrounding our Title Image indicating every constraint that we've just set!
To access each constraint, we may either select it on the navigation or by clicking on one of the blue lines on the screen. Constraint's configuration becomes available in Attributes Inspector:
If we preview our screen in a size other than original, we'll see that the title is positioned properly when other elements are still misaligned. Here's an iPad view for example:
That's an improvement! Let's move onto the next one!
2. Creation Frame
Constraints for Creation view are exactly the same! The nearest neighbor to this view is the title Image - which is exactly what we need to follow:
That was quick!
3. Creation Image Container
This is slightly different - in a good way. We need to snap it to Creation Frame at 10pt - just enable the 4 way distance to the closet neighbor:
We're working at the speed of light! :zorro:
4. Creation Image
This one is identical to the Creation Image Container except the distance will be 0:
Another one down!
5. Startover Button
This one is going to require a bit more effort. The beginning is the same - set width, right and center both - horizontally and vertically:
The trouble is - it got aligned to its containing view - the main screen. o_O Let's adjust that. Select one of the entering constraints we just added and refer to the Attributes Inspector. And change the 'Second view' values to Creation Frame and Bottom reference:
And finally set 'Constant' value to 0, You'll observe the button is now entered vertically to the bottom edge of Creation Frame:
Now repeat the same for the CenterX constraint of Startover Button. This time for second view choose 'Trailing' instead of Bottom (well, Bottom is not an option there). Observe the button has now shifted where we want it to be:
This too is done!
6. Color Label
This one is different again. Let's start with what we already know - set height and follow a neighbor at the top:
Select the constraint for top reference, set the second view to Creation Frame and make sure the constant value is 30:
Two more constraints are missing - left and right sides need to be aligned with Creation Frame. To accomplish that, select both view in navigation and on 'Align' popup check off Leading and Training Edges:
7. & 9. Color Swatch Container & Share Button
Your turn now! Try to constrain the remaining views on your own!
After your are done, your constraint indicators should look like this:
Yay! That's all! Let's look up the storyboard preview:
As with the portrait layout, we did the best we could to fulfill the design requirements, however, the visual appearance can be improved further. This will occur occasionally during your work practice. Don't hesitate to speak with the design team to find the best solutions possible.
What is you need to change the design after you've created all the necessary constraints?
You already know how to modify constraints - by selecting one and adjusting it's setting in the Inspector.
Alternatively, you can move views around in storyboard. For example, if we decided to move our Share button up:
Right away you can see an indicator - orange lines and labels - demonstrating that parameters have changed. In particular, the button has been moved 25pt up.
To resolve this, we can select the related constraint in the navigator and update its constant to 45 (original 20 + 25) or, we can use Resolve Auto Layout Issues popup and request to 'Update Constraint Constants':
How about the main app screen view?
The main view of the app screen need not any constraints. By default at all times it take the whole screen available* for the app. Or, should we say, incorporates 4 constraints - always stick to the top, bottom, left and right at exactly 0pt! :pirate:
*available screen considering the device state, like hotspot is being used or there's an active call on device - in those cases, the app will be shifted down - which also something to consider, by the way, the elements that are constrained to the top but go all the way down could become hidden.
App Launch Screen
We've been focusing on the functional part of our application - and rightly so, however, let's not forget our old friend - lance screen that we implemented in the beginning of the course. It has 2 image views that we aligned within a screen based on our story board design device size. It will surely look different when launched on other sizes. :'(
Implementing Auto Layout on this screen will definitely help!
Test your knowledge:
Identify the constraints that will suit the screen the best.
Implements the designed constraints
Here's an examples:
Logo Image: fix width and height, center to the screen with an offset up
Title Image: fix width and height, center horizontally to the Logo Image, follow the Logo Image at a distance.
Great work! Let's wee what else we can do!
Constraints are layout rules that specify:
parameter within a view.
relationship between two views.
Constraints allow specifying:
Size - direct or relative
Distance - relative to edges or centres
There two rules in Auto Layout:
Constraints must be sufficient to calculate 4 values: x, y, width, height for each view.
Constraints must generate a non conflicting values of size and position.