0
votes

The root view of my onboarding process has a NavigationView. The root view of my app is a login page that also contains a NavigationView. That means when someone launches the app for the first time, they will go through the onboarding process and land at the login screen - resulting in a navigation view within a navigation view.

Is there a way to reset the view stack or simply remove the extra navigation view when necessary?


This is how I implemented @New Dev's solution below. First comes the Tower class. (The name helps me visualize the fact that it's an ObservableObject.) Its job is to keep track of the currentPage and let interested views know when it has changed.
import Foundation
import SwiftUI
import Combine

class Tower: ObservableObject {
    enum Views {
       case onboarding, login, dashboard
    }
    let objectWillChange = PassthroughSubject<Tower, Never>()
    @Published var currentPage: Views = .onboarding {
        didSet {
            objectWillChange.send(self)
        }
    }
}

Next comes the ConductorView. It is notified by the Tower when currentPage changes, and loads the corresponding view.

struct ConductorView: View {
@EnvironmentObject var tower: Tower
    var body: some View {
        VStack {
            if tower.currentPage == .onboarding {
                ContentViewA()
            } else if tower.currentPage == .login {
                ContentViewB()
            }
        }
    }
}

And lastly, a content view.

struct ContentViewA: View {
    @EnvironmentObject var tower: Tower
    var body: some View {
        Button(action: {
            self.tower.currentPage = .login
            }) {
            Text("Go to Login")
            }
        }
    }
}

In addition to New Devs greatly appreciated solution, I also used this article from BLCKBIRDS.

1
you can have a root view (without NavigationView) that sits above all the other flows (onboarding, login, normal app) and switches between then with something like if/elseNew Dev
Would you show your code?Asperi
The comment by @New Dev led me to an article that I think will help. I only know how to transition using a sheet or a navigation link. But if I can do it a third way it may solve the problem. I will update my question as soon as I can.squarehippo10

1 Answers

0
votes

I'll expand on my comment. NavigationView/NavigationLink aren't the only ways to change views - a simple conditional can also be used to determine which view is rendered.

So, say, you have some class that contains the state of the login/onboarding information:

class AppState: ObservableObject {
   enum UserFlow { 
      case onboarding, login, home
   }
   @Published var userFlow: UserFlow = .onboarding
   // ...
}

Then your RootView could determine which user flow to show:

struct RootView: View {

   @EnvironmentObject var appState: AppState

   var body: some View {
      if appState.userFlow == .onboarding {
         OnboardingRootView()
      } else if appState.userFlow == .login {
         LoginRootView()
      } else {
         ContentView()
      }
   }
}