Swift UI 生命周期:如何用新视图替换当前视图?不是简单地推动它

dav*_*ain 2 ios swift swiftui

我有一个按照 SwiftUI 生命周期创建的 SwiftUI 应用程序。我能够毫无问题地推送新视图,但我不知道如何替换视图。我需要实现的是我能够使用此代码在 AppDelegate 生命周期中执行的操作

let bounds = UIScreen.main.bounds
self.window = UIWindow(frame: bounds)
self.window?.rootViewController = rootViewController
self.window?.makeKeyAndVisible()
Run Code Online (Sandbox Code Playgroud)

我尝试在推送新视图时替换根视图并忽略旧视图,但我找不到可行的解决方案。

我尝试使用

presentationMode.wrappedValue.dismiss()
Run Code Online (Sandbox Code Playgroud)

但如果我尝试在推送新视图之前或之后关闭该视图,则它不起作用。

我不知道我是否遗漏了一些东西。

编辑

我尝试使用 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)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是,当我尝试根据令牌的存在更新屏幕变量时,该变量没有得到更新。我试图根据用户登录的条件显示一个视图或另一个视图。此外,我需要从另一个文件中的另一个视图(如 LoginView)更新屏幕变量。我该怎么做 ?

And*_*kyi 5

我发现您想要替换应用程序的根视图。以下是如何使用 SwiftUI 应用程序生命周期执行此操作的简单示例:


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")
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以将其视为MyApp: App常规,您可以ViewSwiftUI其中使用状态替换任何根视图。

编辑

这是代码的更新版本。它使用协调器的非常基本的实现。这里Coordinator也是一个创建视图的工厂。有关更多高级信息,请搜索 MVVM 和特定于 SwiftUI 的协调器。


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()
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)