4

I am trying to change the rootview controller to a different screen after the user has logged out.

    if let window = UIApplication.shared.windows.first {
        window.rootViewController = UIHostingController(rootView: SignInView())
        window.endEditing(true)

        window.makeKeyAndVisible()
    }

This is what I have so far. It navigates to the different view but it makes the buttons on the new new view unusable. Is there a better way to change the rootview or am I missing something?

lazerrouge
  • 89
  • 2
  • 8

3 Answers3

8

My approach is to create an observable object that coordinates navigation between the various app views. Below a simplified example to give you an idea:

//Your app views
enum AppViews {
    case LoginView
    case MainAppView
}

//Class that conforms to the ObservableObject protocol and publishes the viewId property.
//Basically your navigation will react to viewId changes

class ShowingView: ObservableObject {
    
    init(showingView: AppViews) {
        self.viewId = showingView
    }
    
    @Published var viewId : AppViews
}

//The current root view of your app is observing changes of the ShowingView class and switch between your app views
struct AppRootView: View {
    
    @ObservedObject var showingView: ShowingView
    
    var body: some View {
        Group {
            if showingView.viewId == .LoginView {
                TermsAndConditionsView()
                    .environmentObject(showingView)
            }
            else {
                MainAppView()
                    .environmentObject(showingView)
            }
        }
    }
}

Notice that you can pass showingView as environmentObject to your views and use it to switch to another view when required. In your case switch to another screen when the user logs out.

In your scene delegate you can then for example switch between login and main view as follows

var appStartView: AppViews

let isloggedIn = UserDefaults.standard.bool(forKey: "IsLoggedIn")

if isLoggedIn == false {
    appStartView = .LoginView
}
else {
    appStartView = .MainAppView
}

let contentView = AppRootView(showingView: ShowingView(showingView: appStartView))

if let windowScene = scene as? UIWindowScene {
    let window = UIWindow(windowScene: windowScene)
    window.rootViewController = UIHostingController(rootView: contentView)
    self.window = window
    window.makeKeyAndVisible()
}

To switch between MainAppView and LoginView you can simply modify the value of the environmentObject showingView

self.showingView.viewId = AppViews.LoginView

I hope it helps to guide you in the right direction

SwissMark
  • 1,041
  • 12
  • 21
  • Does UserDefaults work like state? So like if it changes, will it re-render the view? – lazerrouge Aug 18 '20 at 05:42
  • 1
    UserDefaults are used for local persistence. You can store values for your preferred keys and retrieve them throughout the app. In this case in the SceneDelegate we just read the value of "IsLoggedIn" when the app starts to be able to check if the user previously logged in or not. If you change the value of "IsLoggedIn" somewhere else it won't cause the app to switch view in real-time. Only the next time your app will start. – SwissMark Aug 18 '20 at 06:35
  • Got it. So I have a Logout button and once the user clicks that, I would like to take back to the LoginView(). So this method won't for that right? – lazerrouge Aug 18 '20 at 06:53
  • 1
    If you follow my example when the user clicks on Logout you modify the value of viewId as written at the end of my answer: self.showingView.viewId = AppViews.LoginView. This will set the LoginView as root view of your app – SwissMark Aug 18 '20 at 07:53
  • Is there a way to pass data between the screens? – lazerrouge Aug 18 '20 at 13:25
  • 1
    I would suggest checking this article from Paul Hudson: https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views his content is an awesome resource to learn SwiftUI. Kindly accept my answer if you think it helped =) – SwissMark Aug 19 '20 at 03:09
-1

Using Below Code you can change root view in SwiftUI

let window = UIApplication.shared.connectedScenes.flatMap { ($0 as? UIWindowScene)?.windows ?? [] }.first{ $0.isKeyWindow}
window?.rootViewController = UIHostingController(rootView: HomeView())
window?.makeKeyAndVisible() 

Set Your View in place of "HomeView()"

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 21 '23 at 19:51
-3

If are you using SceneDelegate.swift file in your project then try this way.

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let scene = (scene as? UIWindowScene) else { return }

        // Instantiate UIWindow with scene
        let window = UIWindow(windowScene: scene)
        // Assign window to SceneDelegate window property
        self.window = window
        // Set initial view controller from Your storyboard as root view controller of UIWindow
        self.window?.rootViewController = UIStoryboard(name: "Your StoryBoard Name", bundle: nil).instantiateInitialViewController()
        // Present window to screen
        self.window?.makeKeyAndVisible()
    }

if you are not using ScanDelegate.swift and go with AppDelegate.swift then try this way.

Without InitalViewController :

func logOut {        
    let storyboard = UIStoryboard(name: "Your StoryBoard", bundle: nil)
    if let navigationController = storyboard.instantiateInitialViewController() as? UINavigationController,
        let loginvc = storyboard.instantiateViewController(withIdentifier: "Your Selected ViewController") as? YourSelectedViewController {
        
        navigationController.viewControllers = [loginvc]
        AppDelegate.getAppDelegate().window?.rootViewController = navigationController
        
    }
}

With InitalViewController :

func logOut() {
        let storyboard = UIStoryboard(name: "Your StoryBoard", bundle: nil)
        let navigationController = storyboard.instantiateInitialViewController()
        AppDelegate.getAppDelegate().window?.rootViewController = navigationController
    }

Extension :

extension AppDelegate {
    
    class func getAppDelegate() -> AppDelegate {
        return UIApplication.shared.delegate as! AppDelegate
    }
    
}
Dixit Akabari
  • 2,419
  • 13
  • 26