对于新的SwiftUI
iOS应用,我在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()
}
用户尚未注册或登录时,将被带到注册流程。
用户注册后,如何将RootView切换到我的TabView?我似乎找不到使用SwiftUI
的解决方案。
我是否应该使用Environment
对象并监听对用户Auth
状态的更改?
答案 0 :(得分:9)
声明一个AppRootView,如下所示:
struct AppRootView: View {
@ObservedObject private var auth: Auth
var body: some View {
Group {
if auth.token != nil {
MainTabbedView()
} else {
StartRegistrationView()
}
}
}
}
,然后在SceneDelegate中将其设置为根视图:
window.rootViewController = UIHostingController(rootView: AppRootView(auth: $auth))
您必须通过像上面那样传递视图或在您的环境中进行设置,将视图绑定到Auth()。 SwiftUI的优点在于,只要令牌不为零,视图就会重新绘制,您的用户会在MainTabbedView中找到它们。
答案 1 :(得分:8)
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()
}
通过使用上述代码,我们可以通过实现上述代码来在单击任何按钮时更改rootView。
答案 2 :(得分:1)
对于某些动画,当更改rootview时,请在sceneDelegate中使用以下代码:
window.rootViewController = UIHostingController(rootView: HomeView())
// A mask of options indicating how you want to perform the animations.
let options: UIView.AnimationOptions = .transitionCrossDissolve
// The duration of the transition animation, measured in seconds.
let duration: TimeInterval = 0.3
// Creates a transition animation.
UIView.transition(with: window, duration: duration, options: options, animations: {}, completion:
{ completed in
// maybe do something on completion here
})
答案 3 :(得分:0)
很好的回答LuLugaga,如果不想使用@Observablebject,则进行更新,这样就不会一直保持更新,可以使用Subject,一旦更新令牌字符串,RootView就会更新。
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)
}
}
答案 4 :(得分:0)
您可以创建一个路由器类
-5
用法:
import Foundation
import UIKit
import SwiftUI
class Router {
class var window: UIWindow? {
if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
if let sceneDelegate = scene.delegate as? SceneDelegate {
let window = UIWindow(windowScene: scene)
sceneDelegate.window = window
window.makeKeyAndVisible()
return window
}
}
return nil
}
static func showMain() {
window?.rootViewController = UIHostingController(rootView: ContentView())
}
}
有了这个,您可以在任何给定时间决定要使用哪个窗口作为根。
答案 5 :(得分:0)
在较新的 Xcode 中,有一些 SwiftUI 模板更改,以下是您的初始视图的加载方式。参考https://developer.apple.com/documentation/swiftui/app
@main
struct AuthCheckApp: App {
var body: some Scene {
WindowGroup {
WelcomeView()
}
}
}
所以在这种情况下,第一个视图是 WelcomeView
并且这个视图负责导航到正确的视图,它可能是登录,主页
struct WelcomeView: View {
@ObservedObject private var auth = Auth()
var body: some View {
if auth.token != nil {
HomeView()
} else {
SignUpView(auth: auth)
}
}
}
Auth 是一个确认 ObservableObject
协议的类,并有一个名为 token 的已发布属性。因此,当此令牌具有值时,它将在上述情况下加载 HomeView
,如果为 nil,它将打开 SignUpView
。
class Auth: ObservableObject {
@Published var token: String?
}
struct SignUpView: View {
let auth: Auth
var body: some View {
VStack {
Text("Hello, please click below button to login")
.padding()
Button("Login") {
print("Loogin Tapped")
auth.token = "TOKEN"
}
}
}
}
struct HomeView: View {
var body: some View {
Text("Welcome Parth!")
.padding()
.background(Color.red)
}
}
如果您有 api 依赖项并且需要等待令牌,那么这种方法将很有帮助,那么您可以将 WelcomeScreen
用作一些飞溅或动画。