I have been working with SwiftUI on my own project right from the start in June 2019. I wanted to share with you how I do my layout system. Before I go into more complex UI design patterns, we will go through the most used options. This first part is how to change the layout. If you want to get to the advanced tools for reactive design, jump ahead to my other post.
When you create a project with SwiftUI, it gives a ContentView as the main default view.
So lets see how we can add things together. You can use VStacks / HStacks to vertically / horizontally lay views next to each other.
As you can see the 3 text views are centered to each other in the VStack. This is the default behavior. If you want a different alignment, you can call a different init like the following example. You have leading, center and trailing for VStacks and top, center and bottom for HStacks.
In order to test this kind of alignment, I am recommending to use the modifiers .border(Color.red), which adds a border with the color red, and .background(Color.gray). This makes it easier to see how large the views are.
If you want to lay out views on top of each other, you can use ZStacks. I gave the 3 views a different size (with .frame()), so you can see how they are positioned.
As you saw, I already used .frame(), which changes the size of the view. This is a very useful view modifier. It has a lot of initializers. You can use absolute values for width or height like so:
Since we want to layout our views on different devices and thus screensizes a more flexible approach is nicer. SwiftUI offers us for this min, ideal and max values for width and height.
Similar to Stacks you can also define the alignment inside the frame. The default behavior is to center the view in the frame. You will have the same options as for the alignment of the ZStack.
Offset and Position
The alignment options so fare are very useful, but what if we wanted something more precise. Take for example a drawing app, where you wanted to define the exact position to draw a rectangle. This is a case for .offset(CGSize) or .position(x:, y:). Let’s see what this does.
Although both rectangles are moved by 100 left and 100 pixel down, you can see that .position() and .offset() give slightly different results. This is because .position puts the center of the view on the given position and .offset() offsets the view by the top left corner. The border() modifier is drawn at the original view position.
Things I have not covered
I am just going to point you to more options here, but I found that knowing the names is a great start to find out more. The .layoutPriority() can help you, if you want to tell swiftUI to layout certain views first, so they get the most space. Adding spacing in stacks with Spacer() and Divider(). Defining your own alignment guides. Adding padding around views with .padding(). A great resource is the swiftui-lab.com.
So now you have a basic understanding on how to layout views. The next question I ask myself was how to define a reactive layout. So that I can have a nice layout on small devices and use the space on larger iPads?. For this we will see how to use SwiftUI in the next part.