[SwiftUI]切换根视图

就一个常见的需求,启动app时先进入LoginView,登录后进入MainView,退出登录后回到

LoginView。

一、使用环境共享状态的方式

在一个视图中使用 @StateObject 声明并初始化一个状态对象(如 rootViewManager),然后通过 @EnvironmentObject 将其注入到视图环境中。在同一个视图树中的其他视图中,可以使用 @EnvironmentObject 来访问这个状态对象。

关键点

  • @StateObject 的作用

    • @StateObject 用于在视图中创建和拥有一个状态对象的实例。它确保对象的生命周期与视图绑定,并且在视图重新加载时不会重新创建。
    • @StateObject 只能用于对象的“创建者”视图。
  • @EnvironmentObject 的作用

    • @EnvironmentObject 是 SwiftUI 的依赖注入机制,用于在视图树中共享状态对象。
    • 通过 @EnvironmentObject 声明的属性,必须由父视图通过 .environmentObject() 注入,否则会导致运行时崩溃。
  • 视图树中状态共享的前提

    • 使用 @EnvironmentObject 的视图,必须位于声明并注入该对象的视图树内。

1. 定义状态对象

创建一个 RootViewManager 类,继承自 ObservableObject

import SwiftUI

class RootViewManager: ObservableObject {
    enum RootView {
        case login
        case 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 SwiftUI

struct RootViewSwitcher: View {
    @EnvironmentObject var rootViewManager: RootViewManager

    var body: some View {
        Group {
            switch rootViewManager.currentRootView {
            case .login:
                LoginView()
            case .main:
                MainView()
            }
        }
    }
}

3. 在子视图中通过 @EnvironmentObject 获取状态

在其他视图中,通过 @EnvironmentObject 获取注入的 RootViewManager,并根据其状态决定显示什么内容。

示例:登录视图

struct LoginView: View {
    @EnvironmentObject var rootViewManager: RootViewManager

    var body: some View {
        VStack {
            Text("登录页面")
            Button("进入主界面") {
                rootViewManager.currentRootView = .main // 切换到主视图
            }
        }
    }
}

示例:主视图

struct MainView: View {
    @EnvironmentObject var rootViewManager: RootViewManager

    var body: some View {
        VStack {
            Text("主界面")
            Button("退出登录") {
                rootViewManager.currentRootView = .login // 切换到登录视图
            }
        }
    }
}

二、使用单例状态对象的方式

如果希望整个项目中全局访问RootViewManager,可以将它设置为单例。

1. 定义状态对象单例

import SwiftUI

class RootViewManager: ObservableObject {
    static let shared = RootViewManager() // 单例
    enum RootView {
        case login
        case main
    }

    @Published var currentRootView: RootView = .main
}

2. 在主视图中注入单例

import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            RootViewSwitcher()
                .environmentObject(RootViewManager.shared) // 注入单例
        }
    }
}

根视图中处理切换逻辑

import SwiftUI

struct RootViewSwitcher: View {
    @EnvironmentObject var rootViewManager: RootViewManager

    var 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 = false

    var body: some Scene {
        WindowGroup {
            if isLogin {
                MainView()
            } else {
                LoginView()
            }  
        }
    }
}

2.登录页登录

import SwiftUI

struct LoginView: View {
    @AppStorage("isLogin") var isLogin: Bool = false

    var body: some View {
        VStack {
            Text("登录页面")
            Button("进入主界面") {
                // 这将自动更新 UserDefaults 中的 "isLogin" 键
                isLogin = true
            }
        }
    }
}

3.首页退出登录

struct MainView: View {
    @AppStorage("isLogin") var isLogin: Bool = false

    var body: some View {
        VStack {
            Text("主界面")
            Button("退出登录") {
                // 这将自动更新 UserDefaults 中的 "isLogin" 键
                isLogin = false
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值