Asko Nõmm

Musings of a Software Engineer

Creating a splash screen in SwiftUI using @AppStorage

20th October, 2020~4 min read

When making an app you often want to greet the user before actually letting said user wonder around the app and for that we use things called Splash Screens. A splash screen is an initial view of the app that greets the user. It's used to set the initial tone and mood of the app. A place where you might want to think about what feeling you want to give to people right before they adventure into your app.

What is @AppStorage?

Available in iOS 14+, macOS 11+ and watchOS 7+, the @AppStorage property wrapper is a convenient way to store relatively small information such as user preferences in your app. An example use of it would be the following:

@AppStorage("fontSize") var fontSize: Int = 14

Which would be useful if you'd let users set their preferred font size and then would save it to app storage for easy access anywhere in the app itself.

Creating a Splash Screen view

For this post we won't be using font size as an example however, we'll be creating a splash screen instead. For this example I'm not making anything special:

struct SplashScreenView: View {
    var onContinue: (() -> Void)
    
    var body: some View {
        VStack {
            Rectangle()
                .fill(Color.black)
                .cornerRadius(25)
                .shadow(color: Color.gray, radius: 15, x: 0, y: 4)
                .frame(width: 85, height: 85)
                .padding(.bottom, 25)
                .overlay(Text("App")
                            .font(.title)
                            .foregroundColor(Color.white))
            
            Text("An app with a flash screen to introduce itself to you and set the initial tone and feeling.")
                .multilineTextAlignment(.center)
                .font(.subheadline)
                .padding(.bottom, 25)
            
            Button(action: onContinue, label: {
                Text("Continue")
            })
        }
        .padding(50)
    }
}

It may seem like a lot of styling mambo-jambo, but there's an important thing to pay attention to here and it's that we'll call a onContinue function when a user taps on the "Continue" button, which is just a callback function we will pass to the SplashScreenView struct when calling it from the parent view, which in our case is ContentView.

It's important because we'll be using this callback to change the variable created with AppStorage which will effectively remove the SplashScreenView from, well, the view. The variable created with AppStorage itself lives in the ContentView, like this:

struct ContentView: View {
    @AppStorage("showSplashScreen") var showSplashScreen: Bool = true
    
    func onContinue() {
        showSplashScreen = false
    }
    
    var body: some View {
        if showSplashScreen {
            SplashScreenView(onContinue: onContinue)
        } else {
            Text("Regular app view goes here :)")
        }
    }
}

You see we define the showSplashScreen variable with the @AppStorage property wrapper, which means if there's a value in app storage, it will read the value to the variable from there and otherwise defaults to what you set it as, which in this example I have set as true, meaning that when there is no value set in app storage (e.g the person is launching the app for the first time) then we show the splash screen.

And the onContinue callback also lives here in ContentView, which is where we set the showSplashScreen as false. From thereon you can see that we're passing the callback onContinue function down to SplashScreenView inside the body of ContentView. And that's how the cookie crumbles.