For a new SwiftUI
iOS app, I do the following in the SceneDelegate
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
if Auth().token == nil {
window.rootViewController = UIHostingController(rootView: StartRegistrationView())
} else {
window.rootViewController = UIHostingController(rootView: MainTabbedView())
}
self.window = window
window.makeKeyAndVisible()
}
When a user hasn't signed up or logged in they are taken to the registration flow.
Once a user has signed up, how can I switch the RootView to go to my TabView? I can't seem to find any solution using SwiftUI
.
Should I instead use an Environment
object and listen for changes to the User's Auth
Status?
wrappedValue. dismiss() from that child view will pop to the root view.
A UIKit view controller that manages a SwiftUI view hierarchy.
A UIKit view controller that manages a SwiftUI view hierarchy. Create a UIHostingController object when you want to integrate SwiftUI views into a UIKit view hierarchy.
You can use SwiftUI with UIKit very easily with the help of UIHostingController. Since UIKit does not speak SwiftUI, let’s introduce a mediator here, UIHostingController! UIHostingController creates a bridge between UIKit and SwiftUI framework. It works as a Container View for SwiftUI view, meaning you can use it as normal UIViewController.
Wrapping UIView or ViewController into SwiftUI is made easy with UIViewControllerRepresentable and UIViewRepresentable. Likewise, it is also possible to have SwiftUI View inside ViewController, by using UIHostingController. The official tutorial is here.
When you want to use SwiftUI in Storyboard IBSegueAction should suffice for most cases, but a subclass of UIHostingController also got its merit. The problem I found which I can't figure out a way to accomplish with IBSegueAction is when I try to assign one on UITabBarController 's root view controllers as 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.
let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene
if let windowScenedelegate = scene?.delegate as? SceneDelegate {
let window = UIWindow(windowScene: scene!)
window.rootViewController = UIHostingController(rootView:ContentView())
windowScenedelegate.window = window
window.makeKeyAndVisible()
}
By using this we can change the rootView in any button click by implementing the above code.
Very good answer LuLugaga, updated if you don't want to use @Observablebject so will not keep updating all the time, you can use Subject, as soon as you update token String, RootView will update.
struct RootView: View {
var loginViewModel: LoginViewModel = LoginViewModel()
@State var tokenString = ""
var body: some View {
Group {
tokenString.count > 0 ? AnyView(ContentView(model: playerViewModel)) : AnyView(LoginView(loginViewModel: loginViewModel))
}.onReceive(loginViewModel.tokenString) {
self.tokenString = $0
}
}
}
class LoginViewModel {
let tokenString = PassthroughSubject<String, Never>()
var token: String {
get { return "" }
set {
self.tokenString.send(newValue)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With