Imagine a typical app that has onboarding, sign-in/registration, and content of some kind. When the app loads you need to make some decision about which view to show. A naive implementation may look like this:
struct ContentView: View {
//assuming some centralized state that keeps track of basic user activity
@State var applicationState = getApplicationState()
var body: some View {
if !applicationState.hasSeenOnboarding {
return OnBoarding()
}
if !applicationState.isSignedIn {
return Registration()
}
return MainContent()
}
}
Obviously this approach fails because SwiftUI views require an opaque return type of some View
. This can be mitigated (albeit hackishly) using the AnyView
wrapper type, which provides type erasure and will allow the code below to compile.
struct ContentView: View {
//assuming some centralized state that keeps track of basic user activity
@State var applicationState = getApplicationState()
var body: some View {
if !applicationState.hasSeenOnboarding {
return AnyView(OnBoarding())
}
if !applicationState.isSignedIn {
return AnyView(Registration())
}
return AnyView(MainContent())
}
}
Is there a more correct way of doing this that doesn't require the use of AnyView
? Is there functionality in the SceneDelegate
that can handle the transition to a completely distinct view hierarchy?
Probably the most SwiftUI
-y way to do things like these is by using the Group
view:
import SwiftUI
struct ContentView: View {
@State private var applicationState = getApplicationState()
var body: some View {
Group {
if !applicationState.hasSeenOnboarding {
OnBoarding()
} else if !applicationState.isSignedIn {
Registration()
} else {
MainContent()
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
The most important thing to note is that, this way, you won't rely on type erasure with AnyView
(to avoid if not strictly necessary).
If you want to encapsulate the initial view creation in a method don't use type erasure. Instead, use the some
keyword:
import SwiftUI
struct ContentView: View {
@State private var applicationState = getApplicationState()
private func initialView() -> some View {
if !applicationState.hasSeenOnboarding {
OnBoarding()
} else if !applicationState.isSignedIn {
Registration()
} else {
MainContent()
}
}
var body: some View {
initialView()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With