iosswiftswiftuinavigationrootview

How can I change root view in SwiftUI (without UIHostingController)?


How can I organize my code in project, so I can easily change Root View from every place of my app?

Is it possible to do it inside @main struct MyApp: App { ... } or I need to create additional intermediate RootView struct?


Solution

  • Found a solution without any additional stuff(e.g. RootView struct). I have here example project with 3 screens, all of them can switch rootView from App struct via NavigationManager.

    Main App struct:

    @main
    struct SwiftUI_TestApp: App {
        
        @StateObject var navigationManager: NavigationManager
        
        init() {
            _navigationManager = StateObject(wrappedValue: NavigationManager(rootScreen: .main))
        }
        
        var body: some Scene {
            WindowGroup {
                switch navigationManager.rootScreen {
                case .content:
                    ContentView()
                        .environmentObject(navigationManager)
                case .main:
                    MainView()
                        .environmentObject(navigationManager)
                case .settings:
                    SettingsView()
                        .environmentObject(navigationManager)
                }
            }
        }
    }
    

    NavigationManager class:

    final class NavigationManager: ObservableObject {
        
        enum Screen: Hashable {
            case main
            case content
            case settings
        }
        
        @Published var rootScreen: Screen
        
        init(rootScreen: Screen) {
            self.rootScreen = rootScreen
        }
    }
    

    ContentView struct:

    struct ContentView: View {
        
        @EnvironmentObject var navigationManager: NavigationManager
        
        var body: some View {
            VStack {
                Text("Content")
                
                Button {
                    navigationManager.rootScreen = .main
                } label: {
                    Text("Show Main")
                }
                
                Button {
                    navigationManager.rootScreen = .settings
                } label: {
                    Text("Show Settings")
                }
            }
        }
    }
    

    MainView struct:

    struct MainView: View {
        
        @EnvironmentObject var navigationManager: NavigationManager
        
        var body: some View {
            VStack {
                Text("Main")
                
                Button {
                    navigationManager.rootScreen = .content
                } label: {
                    Text("Show Content")
                }
                
                Button {
                    navigationManager.rootScreen = .settings
                } label: {
                    Text("Show Settings")
                }
            }
        }
    }
    

    SettingsView struct:

    struct SettingsView: View {
        
        @EnvironmentObject var navigationManager: NavigationManager
        
        var body: some View {
            VStack {
                Text("Settings")
                
                Button {
                    navigationManager.rootScreen = .content
                } label: {
                    Text("Show Content")
                }
                
                Button {
                    navigationManager.rootScreen = .main
                } label: {
                    Text("Show Main")
                }
            }
        }
    }