SwiftUI:如何以编程方式更改Rootview控制器

问题描述

我正在尝试在用户注销后将rootview控制器更改为其他屏幕。

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

        window.makeKeyAndVisible()
    }

这是我到目前为止所拥有的。它导航到其他视图,但是使新的新视图上的按钮不可用。有没有更好的方法来更改rootview或我缺少什么?

解决方法

我的方法是创建一个可观察的对象,以协调各种应用程序视图之间的导航。下面是一个简化的示例,可为您提供一个想法:

//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)
            }
        }
    }
}

请注意,您可以将showingView作为环境对象传递给视图,并在需要时使用它切换到另一个视图。在您的情况下,当用户注销时切换到另一个屏幕。

例如,在您的场景代表中,您可以按以下方式在登录视图和主视图之间切换

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()
}

要在MainAppViewLoginView之间切换,您只需修改environmentObject showingView的值

self.showingView.viewId = AppViews.LoginView

我希望它可以指导您正确的方向

,

如果您在项目中使用 SceneDelegate.swift 文件,请尝试这种方式。

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()
    }

如果您不使用 ScanDelegate.swift ,请使用 AppDelegate.swift ,然后尝试这种方式。

没有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
        
    }
}

使用InitalViewController:

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

扩展名:

extension AppDelegate {
    
    class func getAppDelegate() -> AppDelegate {
        return UIApplication.shared.delegate as! AppDelegate
    }
    
}