Easily Manage State with SwiftUI
Learn how SwiftUI automatically updates your app's UI
With this SwiftTip we demonstrate how to easily manage state.
In this SwiftTip we are going to see how easy it is to keep track of our app’s state with SwiftUI. We will cycle through system images for the weather while automatically updating what is shown to the user with minimal code.
We start by declaring an imageIndex variable on line 8. This variable will be what we use to get the right image to display. By marking it with the @State attribute, SwiftUI will watch for changes in this variable’s value and update our UI automatically wherever it is used.
@State var imageIndex = 0
We see this in action right away on line 12. Here we make a Text object and tell it to display the name of an image based on the value of imageIndex. Whenever imageIndex changes, this Text object will automatically change what it shows.
Text(imageNames[imageIndex])
On line 13 we again see SwiftUI’s state management at work. We create an Image object which shows a built-in system image for the weather based on the name we give it from our imageNames array. Changes in the imageIndex value will also automatically affect what is show in this Image object. Setting the image’s padding to 50 creates 50 points of space around all sides of the image.
Image(systemName: imageNames[imageIndex])
.padding(50)
Next we create an HStack to hold our left and right Button’s, these Button’s allow the user to move through the images. HStack’s space their child content horizontally.
HStack(alignment: .center) {
...
}
We create our left Button on lines 18 to 22. We pass a closure into the action parameter - this will be run whenever the Button is pressed and will decrement the imageIndex variables value by 1. In doing this, the image and text displayed to the user will change without us having to do any additional work!
Button(action: {
self.imageIndex = self.imageIndex - 1
}) {
Image(systemName: "chevron.left").foregroundColor(.black)
}
On line 21, we give our left Button the system’s "chevron.left" image to display. To make this image black we set its foregroundColor property as such.
Image(systemName: "chevron.left").foregroundColor(.black)
On lines 26 to 30, we go through a similar process to make our right Button - this time incrementing the imageIndex variable by 1 instead of decrementing it.
Button(action: {
self.imageIndex = self.imageIndex + 1
}) {
Image(systemName: "chevron.right").foregroundColor(.black)
}
On lines 17 and 25 we have if statements to check whether using each Button still makes sense - whether or not there are more images before or after the one currently displayed. By putting our two Button’s inside of these if statements we tell their enclosing HStack to only show these Button’s if the if statement evaluates to true. If an if statement is false, its Button will not be shown.
if imageIndex > 0 {
...
}
Spacer()
if imageIndex < imageNames.count - 1 {
...
}
And that’s it! No complicated state management with error-prone code to make the updates, SwiftUI handles it all for us.
import SwiftUI
import PlaygroundSupport
struct ContentView : View {
let imageNames: [String] = ["cloud", "cloud.rain", "cloud.bolt", "cloud.sun"]
@State var imageIndex = 0
var body: some View {
VStack {
Text(imageNames[imageIndex])
Image(systemName: imageNames[imageIndex])
.padding(50)
HStack(alignment: .center) {
Spacer()
if imageIndex > 0 {
Button(action: {
self.imageIndex = self.imageIndex - 1
}) {
Image(systemName: "chevron.left").foregroundColor(.black)
}
}
Spacer()
if imageIndex < imageNames.count - 1 {
Button(action: {
self.imageIndex = self.imageIndex + 1
}) {
Image(systemName: "chevron.right").foregroundColor(.black)
}
}
Spacer()
}
}
}
}
let host = UIHostingController(rootView: ContentView())
host.view.frame = CGRect(x: 0, y: 0, width: 375, height: 667)
PlaygroundPage.current.liveView = host
* This article originally appeared in the ZipTips app.
Want to connect?
Contact me to talk about this article, working together or something else.