A SwiftUI Introduction #1: What’s SwiftUI?
At Shadow, we like to share each other’s knowledge about topics we find interesting, whether they are related to Shadow products or not. Last time, I presented to the team an Apple framework I use for some experiments and personal projects.
I am of course talking about SwiftUI, Apple’s latest UI framework.
What’s SwiftUI
Change your way of thinking UIs
Historically, we tend to describe, using code, how our UIs are built. However, SwiftUI is one of the Declarative UI frameworks, and this kind of toolbox requires us to change our way of thinking about UI building.
Stop writing down how to build something you want, start writing down what you want instead. This is the declarative way of thinking.
To stick with Apple’s avocado toast example, stop explaining how to obtain avocado toast:
« Prepare ingredients, gather equipment, toast the bread, place toast on a plate, spread a thin layer of almond butter over toast, cut the avocado in half, and remove its core. »
But instead, describe the toast and its specificities:
« An avocado toast on charred sourdough with almond butter, sea salt, and red pepper flakes. Oh, and make it cut diagonally. »
The original statement was “Oh, and cut it diagonally”, but it’s a clear instruction, so I took the freedom to slightly change the sentence!
To better understand what it means in code, let’s take a look at the following examples:
Imperative Example*
var someView = ContentView()
var someTextView = Text("Hello World!")
var someOtherTextView = Text("How are you?")
someView.spacing = 16.0
someView.layoutDirection = .vertical
someView.alignment = .leading
someTextView.font = SystemFont(size: 14.0)
someTextView.color = .red
someTextView.fontWeight = .bold
someView.addChild(someTextView)
someView.addChild(someOtherTextView)
render(someView)
Declarative Example*
struct ContentView: View {
var body: some View {
VStack(alignment: .leading, spacing: 16) {
Text("Hello, world!")
.font(.system(size: 32.0))
.foregroundColor(.red)
.fontWeight(.bold)
Text("How are you?")
}
}
}
render(ContentView())
* Please note that above examples are not working code snippets, but instead a representation of what it might look like in real code.
One framework to rule them all
SwiftUI not only allows us to create UIs in a declarative manner but also to create adaptative UIs for all Apple systems.
It makes it easier to create Apps working with iOS, iPadOS, watchOS, macOS or tvOS. Your UI is shared in a simpler manner than with XIB. You can make some adjustments if needed, by creating different views that can still use shared views internally, or by adding conditions based on the targeted system directly inside your UI.
It’s also an easy way to get started with Swift development and Apple platforms’ app crafting. No need to learn all the complex mechanisms that make an app work. No need to understand what a ViewController, or a delegate is. Just describe your app, and get started with it! Obviously, that is only true while you’re sticking to quite a simple app, but to get started, it is more than enough.
Organise your views
SwiftUI lets you combine multiple views to describe an interface. For this purpose, SwiftUI provides us with some elementary views called Stacks. A stack just piles up its children in some way, as the name suggests.
VStack
Stacks views in a vertical way.
VStack {
Text("Hello, world!")
Text("How are you?")
}
This will give us something like:
HStack
As expected, it stacks its children horizontally.
HStack {
Image(systemName: "globe")
Text("Hello, world!")
}
This will give us something like:
ZStack
And finally, the ZStack simply put its children on top of each other. The first one declared being below the second, and so on.
ZStack {
Circle()
Text("Hello, world!")
}
This will give us something like:
Combine stacks
Of course, a Stack is still a view like another. Meaning that it can absolutely be the child of another one. And this is exactly how you combine those components to build more complex UIs.
ZStack {
Circle()
VStack {
HStack {
Image(systemName: "globe")
Text("Hello World!")
}
Text("How are you?")
}
}
And this code above will give us something like:
Add style with modifiers
If you tried to reproduce the above examples, you may have noticed that the results you got were somehow different from the screens I have shown to you.
The truth is that I have used some modifiers to make things a little bit prettier!
What are modifiers? Well, they are methods defined by views, that return modified views. Since they are returning views that defined modifiers methods too, you can chain modifiers calls.
Let me show you an example to make things clearer.
Consider the following code:
Text("Hello World! I'm a [...] sirup. A lot.")
Without any modifiers, this is how it looks:
But what if we make this text a little more readable and colorful?
Let’s add those modifiers:
Text("Hello World! I'm a [...] sirup. A lot.")
.font(.title)
.fontWeight(.bold)
.foregroundColor(.red)
.multilineTextAlignment(.center)
.padding()
As you can see, we start by modifying the font, then the weight, we add a little bit of color, we define an alignment for the text, and finally, add some padding to our view. Each call to one of those modifiers returns a new view, on which we can call another modifier.
The result after adding those modifiers will be:
You now have all the basics to start making UIs, in a declarative manner, with SwiftUI. Of course, you’ve got a lot to learn about standard components available in the framework, but I am sure you will find your way through the Apple Documentation!
Want to learn more?
Read the next articles of the series:
- A SwiftUI Introduction #1: What’s SwiftUI? (this one)
- A SwiftUI Introduction #2: Data Flow in SwiftUI
- A SwiftUI Introduction #3: A simple To-Do List