I have a logging onboarding being finished, and I need to present a HomeView, which knows nothing about previous navigation flow.
var body: some View {
if viewModel.isValidated {
destination()
} else {
LoadingView()
}
Doing it this way I have a navigation bar at the top of destination(). I guess I can hide it, but it would still be the same navigation flow and I need to start a new one. How can I achieve that?(iOS 13)
One way to handle this is with an @Environment
object created from a BaseViewModel. The way that this works is to essentially control the state of the presented view from a BaseView
or a view controller. I'll attempt to simplify it for you the best I can.
class BaseViewModel: ObservableObject {
@Published var baseView: UserFlow = .loading
init() {
//Handle your condition if already logged in, change
//baseView to whatever you need it to be.
}
enum UserFlow {
case loading, onboarding, login, home
}
}
Once you've setup your BaseViewModel you'll want to use it, I use it in a switch statement with a binding to an @EnvironmentObject
so that it can be changed from any other view.
struct BaseView: View {
@EnvironmentObject var appState: BaseViewModel
var body: some View {
Group {
switch appState.userFlow {
case .loading:
LoadingView()
case .onboarding:
Text("Not Yet Implemented")
case .login:
LandingPageView()
case .home:
BaseHomeScreenView().environmentObject(BaseHomeScreenViewModel())
}
}
}
}
Your usage, likely at the end of your register/login flow, will look something like this.
struct LoginView: View {
@EnvironmentObject var appState: BaseViewModel
var body: some View {
Button(action: {appState = .home}, label: Text("Log In"))
}
}
So essentially what's happening here is that you're storing your app flow in a particular view which is never disposed of. Think of it like a container. Whenever you change it, it changes the particular view you want to present. The especially good thing about this is that you can build a separate navigation hierarchy without the use of navigation links, if you wanted.