Lesson 3 - Swift UI for different screen sizes and Autolayout
In the previous lesson, Building the UI and introduction to basic components, we created our first Swift app in Xcode. However, it could only display a text label or some other Apple control which we described last time. In today's tutorial, we'll look at very important part of building the UI, which is making the components on the screen aligned where we want them to be.
You probably know that modern websites nowadays can handle different screen sizes (desktop, tablet, cell phone..) and adapt to them. The situation is not that extreme for iOS, but we still have two iPhone sizes (+ the new X model), several iPads and iPhone SE is also still relevant (has the same size as the 5 and 5s models). There are already many display sizes and we should take them into account.
We can make our work easier making the app available for iPhones only. After all, there are less iPads there, but we still have to have different screen sizes in mind. So what should we do? The answer is Autolayout which is the way of defining a responsive UI, adapting to the display size.
If all devices had the same screen size, we could simply put the components at fixed coordinates (e.g. put a label to 20px on the X axis and 40px on the Y axis). As soon as the screen size differs, we have to reposition the controls in the controller to make them fit or to avoid them using only a small portion of the screen. Layouts provide us with this mechanism.
The first layout we'll introduce is
Autolayout. The position of
the controls is defined by constraints. In some programming
languages, these are called anchors, because constraints are
often used to attach a side of the component to the outer container side. We'll
stick with the "constraint" term here.
To make the
Autolayout work correctly, every component must
define how it should be positioned in consideration to other components or to
the edges of the particular controller's UI. There are several ways to achieve
this. We can align a component to both axes, define its distance from other UI
controls and so on. We'll show everything step by step. In different situations,
different approaches are needed.
Autolayout can be complex for beginners, but it's
still the only reasonable way to design the UI so don't avoid it and don't give
Autolayout after several unsuccessful attempts.
Main.storyboard, we can use the project with the
Label from the last lesson. Or you can create a new project and add
some UI components to it. It doesn't matter since we're going to work within
just this single file for now. Let's select
Label, for example, and
align it to the center using constraints. We can do so using the icons in the
bottom right corner of the editor.
We use the Align constraints icon with two rectangles in the center for alignment.
We'll check Vertically in Container and Horizontally in
Container which makes the
Label centered in both directions.
Then we'll just click the Add 2 Constraints assigning the appropriate
alignment constraints to it. The term container refers to the component in which
the control is nested. In this case, this refers to the controller itself. If
Label was e.g. inside of the
View component, which
is by the way often used as the container for other controls or e.g. for
detecting touch gestures, the
View would be the container. This
Label is aligned and will be displayed in the center on
all screen sizes. It's real position (X and Y) will be changed depending on the
screen size of the given device.
Have you been wondering why are we allowed to enter a particular number,
0 by default? In case we wanted to move the
Label to one side, we'd set such a value. E.g. move it a few pixels
vertically above the center. You can try editing the already assigned
constraints in the Size inspector. Since the coordinates start from the top left
corner, we would move the
Label upwards by setting the Y axis
constraint to e.g.
Attaching to sides and limiting the size
Align constraints are especially useful for centering. Now, let's have a look
at position and size constraints. Here, constraints for all four sides have to
be set. Or you can set only two side constraints and define the width and height
of the component. (We can avoid specifying the height using Aspect
ratio.) Only like this the
Autolayout will know where to put
our component at and what size set it to. Of course, you can't set, for example,
constraints for left and right sides and set a fixed width at the same time.
These constraints would be in conflict with each other because attaching the
component to the container on both left and right would make the component
Let's try to position our
Label to the top right corner. Select
it and then click the icon next to the alignment one, which kinda looks like a
This dialog box looks more complicated, but there's nothing to be afraid of. We're interested in the top right corner, so we're going to align from the top and right side. I recommend unchecking Constrain to margins which counts with some inner edges and sometimes doesn't work correctly. I personally encountered the margins not being registered. Also, if you don't use them, you won't make a mistake in sizes etc.
Let's position the
40 pixels from the
top edge and
40 pixels from the right one. You can recognize active
constraint by the solid red line. Clicking in toggles between active/inactive
and also activates entering a new value. Don't forget to set the height and
weight, since we've attached the
Label only to the top and bottom
edges. Otherwise, its size wouldn't be defined. Then just click Add 4
Constraints to anchor the
Label. Now it stays in the top right
corner. You can try it out by switching between different screen sizes - you can
set this in the bottom part of the editor.
Now we introduced the two basic approaches, but that's not all
Autolayout can do.
If you have multiple components in the container,
takes them into account when creating constraints. Now, if we add another
component, e.g. a
Button, the distance constraint for the right
edge of the Button will be calculated from the
Label, which makes
sense. However, you can choose to make it calculate from the controller's edge
again (the down arrow in the value field). I don't recommend it
Before you start setting constraints to other elements like this, it's worth
thinking about the overall design and if you will add more components soon or
change their position. Don't be afraid of using
View as the
container for components that relate to each other. You'll then set the
constraints from the edges of this
View and you can move the view
itself easily. You can also temporarily set distinct background colors to
Views to see how they are positioned.
Conflicts between constraints
Sometimes it may happen that
Autolayout will get "mad at
us" for bad constraints. In that case, you may have forgotten to set
everything needed or you accidentally added duplicate constraint.
Button can't be e.g.
0 from the left edge and at the
same time have a different constraint set to
20 also from the left
edge. Xcode will fairly well show you where's the problem and hints a fix
"with one click". I personally don't use these fixes because it often
ends up differently than what I wanted. I also almost never use Reset to
suggested constraints which sets the constraints for you. Maybe you'll be
comfortable with these options, just try them out. Remember that you will find
constraints in the Size inspector of individual components.
In the next lesson, Simple iOS calculator in Swift, we'll finally look at something more
real-world-ish and create a simple iOS calculator. We'll learn to use
StackView and connect the UI with the code.
No one has commented yet - be the first!