Celebrating 200 Daily Coding Tips 🎉 all tutorials will be free to all this week!
The temptation with VStack
or HStack
is to use a Spacer
to push content around. A Spacer
expands to fill all available space, making it perfect for moving views to the right position within their layout container. Want to push content to the top? Put it in a VStack
with a Spacer
below it. Want to push it to the right? Put it in an HStack
with a Spacer
on the left.
But what if I told you that you don’t need a VStack
or an HStack
in these situations?
My first example aims to centre a Text
that displays the UK English word centred. I’m providing ContentView
, which has no Spacer
, and ContentViewWithSpacers
which has two. Both have a maxWidth
of .infinity
, because otherwise they would only be the width of the Text
.
I want them to take up as much space as possible, because I’m displaying them in ContentView_Previews
in a VStack
.
Both of these give the Text
a black background and white font colour, and I couldn’t resist rounding the corners with .cornerRadius
as well. The main reason I added a background was to make the point that backgrounds are frozen in time. What do I mean by that? My background is added after the padding, making the background only slightly larger than the Text
. If I increase the size of the frame after adding a background, the background remains at the same size it was.
For a long time I’ve placed views inside a Group
to which I've added .frame(maxWidth: .infinity, maxHeight: .infinity)
. This gives me a container that can be given its own background, while leaving the view it contains intact.
This is actually not necessary, because every view can be seen as having the opportunity to create unlimited frames.
Here’s how it ends up looking:
As you can see, the two views look identical except for their background colour.
The view at the bottom has managed to add padding and a background to the Text
, expand its frame, and then add the red background afterwards. You might notice that I haven’t specified an alignment either. Specifying alignment: .center
is redundant, because the default value for the alignment parameter is already .center
.
If I add alignment: .leading to the VStack
of the blue ContentViewWithSpacers
, it will behave the same way as if I add that alignment to ContentView
before the red background is added.
There is no need for a ZStack
to place the background behind the Text
in ContentView
, even though it was already given a background once.
But what if I add an alignment of .bottomTrailing
?
This is where Spacer
starts to create problems.
ContentView
is free to lay a view out anywhere on the screen, because there are no other views that are resisting compression. But ContentViewWithSpacers
requires that I remember to remove a Spacer
. When I do that, I can actually use an alignment of .trailing
, because the Text
is already being shoved to the bottom by the remaining Spacer
above it.
This is how using Spacer
will actually complicate your layout, because alignments don’t actually mean what you expect them to mean.