提问人:dave.rain 提问时间:1/28/2022 最后编辑:dave.rain 更新时间:4/11/2022 访问量:1341
Swift UI 生命周期:如何用新视图替换当前视图?不是简单地推动它
Swift UI Lifecycle: how to replace the current view with a new one ? Not simply pushing it
问:
我有一个按照 SwiftUI 生命周期创建的 SwiftUI 应用程序。我能够毫无问题地推送新视图,但我无法弄清楚如何替换视图。 我需要实现的是我在 AppDelegate 生命周期中使用此代码能够执行的操作
let bounds = UIScreen.main.bounds
self.window = UIWindow(frame: bounds)
self.window?.rootViewController = rootViewController
self.window?.makeKeyAndVisible()
我尝试替换根视图并在推送新视图时关闭旧视图,但我找不到有效的解决方案。
我试着用
presentationMode.wrappedValue.dismiss()
但是,如果我试图在我推送新视图之前或之后关闭视图,则不起作用。
我不知道我是否错过了什么。
编辑
我尝试使用ViewGroup实现解决方案
import SwiftUI
// Specify all root level screens
enum Screen {
case login
case users
}
@main
struct IosstarterkitApp: App {
var loginV: AnyView
var userV: AnyView
// Use @State for current screen
@State var screen: Screen = .login
init() {
// instantiate the factory for the dependency injection
let baseProviderFactory: BaseProviderProtocol = BaseProviderFactory()
// Create the SwiftUI views that provides the window contents.
var userView = UserView(store: UserStore())
userView.setPresenter(presenter: baseProviderFactory.getUserPresenter() as! BasePresenterProtocol)
userV = AnyView(userView)
var loginView = LoginView(store: LoginStore())
loginView.setPresenter(presenter: baseProviderFactory.getLoginPresenter() as! BasePresenterProtocol)
loginV = AnyView(loginView)
let userDefaultRepository = UserDefaultsRepository()
if userDefaultRepository.getAccessToken() != nil {
self.screen = .users
} else {
self.screen = .login
}
}
var body: some Scene {
WindowGroup {
switch screen {
case .login:
RootView(view: loginV)
case .users:
RootView(view: userV)
}
}
}
}
问题是,当我尝试根据令牌的存在更新屏幕变量时,该变量没有得到更新。我正在尝试根据用户被记录的条件显示视图或其他视图。 此外,我需要从另一个文件中的另一个视图(如 LoginView)更新 screen 变量。我该怎么做?
答:
5赞
Andrew Bogaevskyi
1/28/2022
#1
我看到您要替换应用程序的根视图。下面是如何使用 SwiftUI App 生命周期的简单示例:
import SwiftUI
// Specify all root level screens
enum Screen {
case onboarding
case home
}
@main
struct MyApp: App {
// Use @State for current screen
@State var screen: Screen = .onboarding
var body: some Scene {
WindowGroup {
switch screen {
case .onboarding:
OnboardingView {
screen = .home
}
case .home:
HomeView()
}
}
}
}
struct OnboardingView: View {
let openHome: () -> Void
var body: some View {
VStack {
Text("OnboardingView")
Button("Open Home") {
openHome()
}
}
}
}
struct HomeView: View {
var body: some View {
Text("HomeView")
}
}
您可以将 视为常规视图,您可以在其中使用 state 替换任何根视图。MyApp: App
View
SwiftUI
编辑
这是代码的更新版本。它使用了 Coordinator 的非常基本的实现。这里 Coordinator 也是一个用于创建视图的工厂。有关更高级的信息,请搜索特定于 SwiftUI 的 MVVM with Coordinator。
enum Screen {
case login
case users
}
final class AppCoordinator: ObservableObject {
@Published var screen: Screen = .login
private let userDefaultRepository = UserDefaultsRepository()
private let providerFactory: BaseProviderProtocol = BaseProviderFactory()
init() {
if userDefaultRepository.getAccessToken() != nil {
screen = .users
} else {
screen = .login
}
}
func userView() -> some View {
let store = UserStore()
let presenter = baseProviderFactory.getUserPresenter() as! BasePresenterProtocol
return UserView(store: store, presenter: presenter)
}
func loginView() -> some View {
let store = LoginStore()
let presenter = baseProviderFactory.getLoginPresenter() as! BasePresenterProtocol
return LoginView(store: LoginStore(), presenter: presenter)
}
}
@main
struct IosstarterkitApp: App {
@StateObject var coordinator = AppCoordinator()
var body: some Scene {
WindowGroup {
switch coordinator.screen {
case .login:
coordinator.loginView()
case .users:
coordinator.userView()
}
}
}
}
评论
0赞
dave.rain
2/1/2022
谢谢你的回答。我已经找到了这个解决方案,并根据您的建议更新了问题描述。问题是我很难尝试使它适应我的代码。你有什么建议吗?
0赞
Andrew Bogaevskyi
2/1/2022
@dave.rain 您正在尝试应用 UIKit 中的方法,将视图存储在 properties 和 中。这不是 SwiftUI 的方式。让我更新一下我的答案。我不知道 UserView 和 LoginView 的实现,但最好避免使用这样的属性。为此,您可以使用 init 注入 use a ViewModel。UserView
setPresenter
0赞
dave.rain
2/2/2022
谢谢。我在想这个问题,但我不确定。我会尝试这种方法。
0赞
dave.rain
2/6/2022
它正在工作。多谢。
评论