Root-> A ->B -> C page, 当前C page, 如何返回B,又如何直接返回A page呢

在 SwiftUI 中,从 C 页面返回到 B 或直接返回到 A 页面有多种方式。以下是具体的实现方法:

基本设置

swift 复制代码
enum Route: Hashable {
    case a
    case b
    case c
}

struct ContentView: View {
    @State private var navigationPath = NavigationPath()
    
    var body: some View {
        NavigationStack(path: $navigationPath) {
            AView()
                .navigationDestination(for: Route.self) { route in
                    switch route {
                    case .a:
                        AView()
                    case .b:
                        BView()
                    case .c:
                        CView()
                    }
                }
        }
        .environment(\.navigationPath, $navigationPath)
    }
}

2. 从 C 返回 B,或直接返回 A

使用环境变量传递导航控制

swift 复制代码
// 定义环境Key
struct NavigationPathKey: EnvironmentKey {
    static let defaultValue: Binding<NavigationPath>? = nil
}

extension EnvironmentValues {
    var navigationPath: Binding<NavigationPath>? {
        get { self[NavigationPathKey.self] }
        set { self[NavigationPathKey.self] = newValue }
    }
}

// A 页面
struct AView: View {
    @Environment(\.navigationPath) private var navigationPath
    
    var body: some View {
        VStack {
            Text("A 页面")
            
            Button("前往 B 页面") {
                navigationPath?.wrappedValue.append(Route.b)
            }
            .padding()
        }
        .navigationTitle("A 页面")
    }
}

// B 页面
struct BView: View {
    @Environment(\.navigationPath) private var navigationPath
    
    var body: some View {
        VStack {
            Text("B 页面")
            
            Button("前往 C 页面") {
                navigationPath?.wrappedValue.append(Route.c)
            }
            .padding()
        }
        .navigationTitle("B 页面")
    }
}

// C 页面 - 关键部分
struct CView: View {
    @Environment(\.navigationPath) private var navigationPath
    @Environment(\.dismiss) private var dismiss
    
    var body: some View {
        VStack(spacing: 20) {
            Text("C 页面")
            
            // 方法1: 返回上一页 (B)
            Button("返回上一页 (B)") {
                dismiss() // 或者 navigationPath?.wrappedValue.removeLast()
            }
            
            // 方法2: 直接返回 A 页面
            Button("直接返回 A 页面") {
                // 移除最后2个页面 (C 和 B)
                navigationPath?.wrappedValue.removeLast(2)
            }
            
            // 方法3: 返回根页面 (A)
            Button("返回根页面 (A)") {
                // 移除所有页面,回到根
                navigationPath?.wrappedValue.removeLast(navigationPath?.wrappedValue.count ?? 0)
            }
            
            // 方法4: 特定路径跳转
            Button("跳转到 A 页面") {
                // 清空路径,然后添加 A
                navigationPath?.wrappedValue = NavigationPath()
                navigationPath?.wrappedValue.append(Route.a)
            }
        }
        .navigationTitle("C 页面")
    }
}

3. 使用导航管理器 (推荐)

创建导航管理器

swift 复制代码
class NavigationManager: ObservableObject {
    @Published var path = NavigationPath()
    
    // 返回上一页
    func goBack() {
        guard !path.isEmpty else { return }
        path.removeLast()
    }
    
    // 返回到特定页面
    func goBackToA() {
        // 假设路径是 [B, C],移除最后2个
        if path.count >= 2 {
            path.removeLast(2)
        }
    }
    
    // 返回到根页面
    func goToRoot() {
        path.removeLast(path.count)
    }
    
    // 导航到特定页面
    func navigateTo(_ route: Route) {
        path.append(route)
    }
}

在视图中使用

swift 复制代码
struct AppView: View {
    @StateObject private var navManager = NavigationManager()
    
    var body: some View {
        NavigationStack(path: $navManager.path) {
            AView()
                .navigationDestination(for: Route.self) { route in
                    switch route {
                    case .a: AView()
                    case .b: BView()
                    case .c: CView()
                    }
                }
        }
        .environmentObject(navManager)
    }
}

// C 页面使用导航管理器
struct CView: View {
    @EnvironmentObject private var navManager: NavigationManager
    @Environment(\.dismiss) private var dismiss
    
    var body: some View {
        VStack(spacing: 20) {
            Text("C 页面")
            
            Button("返回上一页 (B)") {
                navManager.goBack()
            }
            .buttonStyle(.bordered)
            
            Button("直接返回 A 页面") {
                navManager.goBackToA()
            }
            .buttonStyle(.borderedProminent)
            
            Button("返回根页面") {
                navManager.goToRoot()
            }
            .buttonStyle(.bordered)
            
            // 当前路径信息
            Text("当前导航栈深度: \(navManager.path.count)")
        }
        .navigationTitle("C 页面")
        .navigationBarBackButtonHidden(true) // 隐藏默认返回按钮
        .toolbar {
            ToolbarItem(placement: .navigationBarLeading) {
                Button("返回") {
                    navManager.goBack()
                }
            }
        }
    }
}

4. 使用 @Binding 传递控制 (简单场景)

swift 复制代码
struct CView: View {
    @Binding var path: NavigationPath
    
    var body: some View {
        VStack {
            Text("C 页面")
            
            Button("返回 B") {
                path.removeLast()
            }
            
            Button("返回 A") {
                // 移除 B 和 C
                if path.count >= 2 {
                    path.removeLast(2)
                }
            }
        }
    }
}

总结

从 C 返回 B 的方法:

  • dismiss() - 最简单的返回上一页
  • navigationPath.removeLast() - 编程式返回
  • navManager.goBack() - 通过管理器返回

从 C 直接返回 A 的方法:

  • navigationPath.removeLast(2) - 移除最后2个页面
  • navigationPath.removeLast(navigationPath.count) - 清空所有页面
  • navManager.goBackToA() - 通过管理器精确控制

推荐使用导航管理器的方式,因为它提供了更好的代码组织和可维护性。

相关推荐
宠..6 分钟前
创建标签控件
java·服务器·开发语言·前端·c++·qt
Z_Wonderful7 分钟前
主题切换(1):css变量的使用(:root)
前端·javascript·css
亮子AI9 分钟前
【CSS】如何选择父级元素?
前端·css
Z_Wonderful10 分钟前
主题切换(2):CSS 变量(自定义属性)
前端·javascript·css
m0_7400437315 分钟前
html练习题
开发语言·前端·javascript
qq_4179165316 分钟前
HTML中的列表
android·前端·html
yqcoder18 分钟前
Vue2 和 Vue3 中祖先组件和子孙组件的通信方法和区别
前端·javascript·vue.js
勇气要爆发19 分钟前
问:当服务器资源有限,前端项目高并发优化策略
前端·性能优化
鹏多多19 分钟前
前端组件二次封装实战:Vue+React基于Element UI/AntD的高效封装策略
前端·vue.js·react.js