Creating a Simple SwiftUI App
SwiftUI is Apple’s new framework for building user interfaces in Swift. Let’s introduce SwiftUI by creating a simple app. The app displays the number of times you tap a button. I couldn’t think of a simper app idea.
I’m going to focus on making an iOS app in the article, but you can also make a Mac version of this app. Create a macOS App project instead of an iOS project.
Apple added SwiftUI support in Xcode 11 so you must be running Xcode 11 or higher to use SwiftUI.
Create the Project
Create a single-view iOS app (App on Xcode 12) project. Choose SwiftUI from the User Interface menu. Deselect all the checkboxes.
When you create the project, the project navigator should look similar to the following screenshot:
The file you’re going to edit in this article is ContentView.swift
. This file contains the main view for the app’s user interface. You will be adding controls to the content view.
The Content View
Open the ContentView.swift
file. You’ll see the following struct for the content view:
struct ContentView: View {
var body: some View {
Text("Hello, World!")
}
}
The body
property contains the main view. In the code Apple supplies, the view consists of a label (the Text
struct is a label) with the text Hello, World!
. If you build and run the project, you will see the label.
Previews and the Canvas
If you look at the end of the ContentView.swift
file, you’ll see the following struct:
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
That struct is for displaying a preview of the view in Xcode’s canvas. The canvas is next to the Swift file in Xcode so you can view your source code and the canvas side by side..
I’m not going to use previews and the canvas in this article. I find the canvas gets in the way, is flaky, and doesn’t help much. But the canvas is there for you if you want it. You can toggle the canvas on and off using a button on the right side of the jump bar.
The button is at the top left in the screenshot.
Change the Label
Let’s start by changing the label’s text to Taps:
. Change the code for body
to the following:
var body: some View {
Text("Taps: ")
}
Build and run the project, and you should see the label’s text is Taps:
.
You can modify how the text in the label looks using functions and properties of the Text
struct. Start with a period. The following code displays the label in bold text:
var body: some View {
Text("Taps: ")
.bold()
}
The following code changes the font to the system title font:
var body: some View {
Text("Taps: ")
.font(.title)
}
Add a Variable to Store the Tap Count
To display the number of times someone taps the button, you need a variable to store the number of taps. Add the following code before the body
variable:
@State var taps = 0
You must use the @State
property wrapper so you can change the value of taps
when someone taps the button. If you omit the @State
part, you will get a compiler error saying that you’re trying to change an immutable value.
Now modify the label so it also shows the number of taps.
Text("Taps: \(taps)")
Build and run the project. The label will show zero taps.
Place the Label in a Stack
The next logical step is to add a button. But you can’t just add the button after the label.
var body: some View {
Text("Taps: ")
.font(.title)
// This won't compile.
Button("Tap Me") {
}
}
The compiler will complain about that code. You have to place the label and button inside a stack. Start by placing the label inside a stack.
VStack {
Text("Taps: \(taps)")
.font(.title)
}
I placed the label in a vertical stack. When you add the button, it will appear below the label. Build and run the project. There aren’t any visible changes, but you’re ready to add the button now.
Add the Button
Let’s add the button to the stack in the content view.
VStack {
Text("Taps: \(taps)")
.font(.title)
Button("Tap Me") {
self.taps += 1
}
}
The button’s title, Tap Me
, is in parentheses. A closure for the button’s action (what happens when someone taps the button) follows. For this app you increment the taps
variable. If you have more complicated behavior, write a function and call that function from the closure.
Build and run the project. The number of taps increases each time you tap the button.
Add Space Between the Label and Button
The app works, but there’s not much space between the label and button. Use the padding
function to add some padding between the label and button.
VStack {
Text("Taps: \(taps)")
.font(.title)
.padding()
Button("Tap Me") {
self.taps += 1
}
}
If you supply no arguments, the padding
function adds a small amount of space. To add more space, you can supply the edge to apply the padding and the amount. The following line of code provides 100 points of padding at the bottom:
.padding(.bottom, 100)
When you build and run the project, you should see better spacing between the label and button.
Challenge
Add a Reset button that sets the taps
variable back to zero. Don’t forget to add padding between the two buttons. I have the project on GitHub if you get stuck.