就一个常见的需求,启动app时先进入LoginView,登录后进入MainView,退出登录后回到
LoginView。
一、使用环境共享状态的方式
在一个视图中使用 @StateObject 声明并初始化一个状态对象(如 rootViewManager),然后通过 @EnvironmentObject 将其注入到视图环境中。在同一个视图树中的其他视图中,可以使用 @EnvironmentObject 来访问这个状态对象。
关键点
-  @StateObject的作用:- @StateObject用于在视图中创建和拥有一个状态对象的实例。它确保对象的生命周期与视图绑定,并且在视图重新加载时不会重新创建。
- @StateObject只能用于对象的“创建者”视图。
 
-  @EnvironmentObject的作用:- @EnvironmentObject是 SwiftUI 的依赖注入机制,用于在视图树中共享状态对象。
- 通过 @EnvironmentObject声明的属性,必须由父视图通过.environmentObject()注入,否则会导致运行时崩溃。
 
-  视图树中状态共享的前提: - 使用 @EnvironmentObject的视图,必须位于声明并注入该对象的视图树内。
 
- 使用 
1. 定义状态对象
创建一个 RootViewManager 类,继承自 ObservableObject:
import SwiftUIclass RootViewManager: ObservableObject {enum RootView {case logincase main}@Published var currentRootView: RootView = .main
}2. 在主视图中声明 @StateObject 并注入环境
 
在主视图中使用 @StateObject 创建并管理 RootViewManager 的实例,同时通过 .environmentObject() 将其注入到视图树中。
import SwiftUI@main
struct MyApp: App {@StateObject private var rootViewManager = RootViewManager() // 创建状态对象var body: some Scene {WindowGroup {RootViewSwitcher() // 根视图.environmentObject(rootViewManager) // 注入状态对象到环境中}}
}根视图中处理切换逻辑
import SwiftUIstruct RootViewSwitcher: View {@EnvironmentObject var rootViewManager: RootViewManagervar body: some View {Group {switch rootViewManager.currentRootView {case .login:LoginView()case .main:MainView()}}}
}3. 在子视图中通过 @EnvironmentObject 获取状态
 
在其他视图中,通过 @EnvironmentObject 获取注入的 RootViewManager,并根据其状态决定显示什么内容。
示例:登录视图
struct LoginView: View {@EnvironmentObject var rootViewManager: RootViewManagervar body: some View {VStack {Text("登录页面")Button("进入主界面") {rootViewManager.currentRootView = .main // 切换到主视图}}}
}示例:主视图
struct MainView: View {@EnvironmentObject var rootViewManager: RootViewManagervar body: some View {VStack {Text("主界面")Button("退出登录") {rootViewManager.currentRootView = .login // 切换到登录视图}}}
}二、使用单例状态对象的方式
如果希望整个项目中全局访问RootViewManager,可以将它设置为单例。
1. 定义状态对象单例
import SwiftUIclass RootViewManager: ObservableObject {static let shared = RootViewManager() // 单例enum RootView {case logincase main}@Published var currentRootView: RootView = .main
}2. 在主视图中注入单例
import SwiftUI@main
struct MyApp: App {var body: some Scene {WindowGroup {RootViewSwitcher().environmentObject(RootViewManager.shared) // 注入单例}}
}根视图中处理切换逻辑
import SwiftUIstruct RootViewSwitcher: View {@EnvironmentObject var rootViewManager: RootViewManagervar body: some View {Group {switch rootViewManager.currentRootView {case .login:LoginView()case .main:TabbarView()}}}
}3.在其他所有类中都可以获取和改变状态
class Tools {/// 切换到主界面static func enterMainView() {RootViewManager.shared.currentRootView = .main}/// 切换到登录界面static func enterLoginView() {RootViewManager.shared.currentRootView = .login}
}
三、使用@AppStorage属性包装器的方式
1.在主视图使用@AppStorage监听UserDefaults中特定键的变化
import SwiftUI@main
struct MyApp: App {/*使用 @AppStorage 属性包装器可以方便地监听 UserDefaults 中特定键的变化。当使用 @AppStorage 来包装一个变量时,它会自动监听 UserDefaults 中与该变量关联键的变化,并在值改变时更新界面。*/@AppStorage("isLogin") var isLogin: Bool = falsevar body: some Scene {WindowGroup {if isLogin {MainView()} else {LoginView()}  }}
}2.登录页登录
import SwiftUIstruct LoginView: View {@AppStorage("isLogin") var isLogin: Bool = falsevar body: some View {VStack {Text("登录页面")Button("进入主界面") {// 这将自动更新 UserDefaults 中的 "isLogin" 键isLogin = true}}}
}3.首页退出登录
struct MainView: View {@AppStorage("isLogin") var isLogin: Bool = falsevar body: some View {VStack {Text("主界面")Button("退出登录") {// 这将自动更新 UserDefaults 中的 "isLogin" 键isLogin = false}}}
}