Change the Root View of Uihostingcontroller in Swiftui

Change the root view of UIHostingController in SwiftUI

Declare an AppRootView, something like this:

struct AppRootView: View {

@ObservedObject private var auth: Auth
var body: some View {
Group {
if auth.token != nil {
MainTabbedView()
} else {
StartRegistrationView()
}
}
}
}

and then in SceneDelegate set it as the root view:

window.rootViewController = UIHostingController(rootView: AppRootView(auth: $auth))

You have to bind your view to your Auth() either by passing it in as I did above or by setting it on your environment. The beauty of SwiftUI is that as soon as the token is not nil, the view will redraw and your user will find them selves in MainTabbedView.

How do I change the root view with SwiftUI

You just display each view conditionally in a root view

var body: some View {
if isLoggedIn {
HomeView()
} else {
LoginView() {
}
}

What is equivalent to 'window.rootViewController' in WindowGroup - SwiftUI

With the help of comments and some tutorials, I reached out to the solution (Tested on iOS 15, Xcode 13.2.1):

Add the following code to the Main App Launcher.

struct MyApp: App {

@StateObject var appState = AppState.shared

var body: some Scene {
WindowGroup {
SplashScreenView().id(appState.environment)
}
}
}

And then I created the AppState class, which is the class that when changes I will change the window.

class AppState: ObservableObject {
static let shared = AppState()
@Published var environment = "Production"
}

And whenever I wanted to change the environment and do the same functionality of changing window in UIKit , do the following :

AppState.shared.environment = "Pre-Production"

How to push a new root view using SwiftUI without NavigationLink?

Here is possible alternate approach of how to replace root view completely... using notifications

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

let loginRootViewNotification =
NSNotification.Name("loginRootViewNotification") // declare notification
private var observer: Any? // ... and observer

...
// in place of window creation ...
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)

observer = NotificationCenter.default.addObserver(forName: loginRootViewNotification, object: nil, queue: nil, using: { _ in
let anotherRootView = AnotherRootView()
// create another view on notification and replace
window.rootViewController = UIHostingController(rootView: anotherRootView)
})

in your desired place post needed notification

Button(action: { 
// launch new root view here
NotificationCenter.default.post(loginRootViewNotification)
}, label: {Text("Login")}).padding()

SwiftUI - How to access UIHostingController from SwiftUI

Here is a demo of possible approach - to use external configuration wrapper class to hold weak link to controller and inject it into SwiftUI view (as alternate it is also possible to make it ObservableObject to combine with other global properties and logic).

Tested with Xcode 12.5 / iOS 14.5

class Configuration {
weak var hostingController: UIViewController? // << wraps reference
}

struct SwiftUIView: View {
let config: Configuration // << reference here

var body: some View {
Button("Demo") {
self.config.hostingController?.title = "New Title"
}
}
}

let configuration = ExtConfiguration()
let controller = UIHostingController(rootView: SwiftUIView(config: configuration))

// injects here, because `configuration` is a reference !!
configuration.hostingController = controller

controller.title = "title"
MyNavigationManager.present(controller)


Related Topics



Leave a reply



Submit