前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >SwiftUI中navigationDestination用法

SwiftUI中navigationDestination用法

作者头像
莫空9081
发布2024-11-20 14:01:57
发布2024-11-20 14:01:57
11900
代码可运行
举报
文章被收录于专栏:iOS 备忘录iOS 备忘录
运行总次数:0
代码可运行

背景

最近做 SwiftUI 项目,之前对于 navigationDestination 的用法理解不太深刻,觉得很是难用,最近发现了正确的使用方式,这里记录一下。

场景

假设有一个 TabView 类为 A,A 有 B、C 两个Tab,C 的 Tab 下子界面有 D,D 的子界面有 E。

即有 A -> B 和 A -> C -> D -> E 两条链路。

之前的用法是:

代码语言:javascript
代码运行次数:0
复制

struct A: View {
    var body: some View {
        NavigationStack {
            TabView(selection: $selectedTab) {
                B()
                C()
            }
        }
    }
}

struct B: View {

}

struct C: View {
    @State private var navigateToD: Bool = false

    var body: some View {
        VStack {
            xxx
            Button {
                navigateToD.toggle()
            } label: {
                Text("NavigateToD")
            }
        }
        .navigationDestination(isPresented: $navigateToD) {
            D()
        }
    }
}

struct D: View {
    @State private var navigateToE: Bool = false

    var body: some View {
        VStack {
            xxx
            Button {
                navigateToE.toggle()
            } label: {
                Text("NavigateToD")
            }
        }
        .navigationDestination(isPresented: $navigateToE) {
            E()
        }
    }
}

struct E: View {
    xxx
}

这里面简单的使用确实没问题,每个界面的返回可以通过 Environment 的dismiss 来实现。但是如果想要实现从 E 返回到 C 就非常麻烦了。而且,这里每一步的跳转都散落在各个类里,没有统一的地方管理,后续维护也不易。

所以针对上面存在的问题,对使用进行了优化,

针对TabView 的两个子视图,B 和 C,分别用NavigationStack包装。不要把NavigationStack放在TabView的外层,因为遇到了放在这里,针对navigationDestination做跳转的时候,遇到了跳转多次的问题。

声明一个BNavCoordinatorCNavCoordinator,分别用于管理BC的跳转。在具体的NavCoordinator中,声明一个枚举管理这个页面下的所有子界面。然后创建NavCoordinator,实现pushpoppopToRootnavigator方法。 示例代码如下:

代码语言:javascript
代码运行次数:0
复制
enum CNavScreens: Hashable {
    case d(param1: Int, param2: String)
    case e
}

struct CNavCoordinator: ObservableObject {
    @Published var paths = NavigationPath()

    @ViewBuilder
    func navigate(to screen: CNavScreens) -> some View {
        switch screen {
            case .d(let param1, let param2):
                D(param1: param1, param2: param2)
            case  .e:
                E()
        }
    }


   // add screen
   func push(_ screen: TGICustomerScreens) {
       paths.append(screen)
   }
   
   // remove last screen
   func pop() {
       paths.removeLast()
   }
   
   // popToRoot
   func popToRoot() {
       paths.removeLast(paths.count)
   }
}

然后在具体页面中使用,示例如下

代码语言:javascript
代码运行次数:0
复制

struct A: View {
    var body: some View {
         TabView(selection: $selectedTab) {
             B()
             C()
         }
    }
}

struct B: View {

}

struct C: View {
    @StateObject var cNavCoordinator = CNavCoordinator()

    var body: some View {
        NavigationStack {
          VStack {
              xxx
              Button {
                let screen = CNavScreens.d(param1: param1, param2: param2)
                cNavCoordinator.push(screen)
              } label: {
                  Text("NavigateToD")
              }
          }
          .environmentObject(navCoordinator)
          .navigationDestination(for: CustomScreens.self) { path in
              navCoordinator.navigate(to: path)
                  .environmentObject(navCoordinator)
                  .environmentObject(xxx)
                  .environmentObject(yyy)
          }
        }
    }
}

struct D: View {
    @EnvironmentObject var cNavCoordinator: CNavCoordinator

    var body: some View {
        VStack {
            xxx
            Button {
                let screen = CNavScreens.e
                cNavCoordinator.push(screen)
            } label: {
                Text("NavigateToD")
            }
        }
    }
}

struct E: View {
     @EnvironmentObject var cNavCoordinator: CNavCoordinator

    var body: some View {
        VStack {
            xxx
            Button {
                // cNavCoordinator.pop()
                cNavCoordinator.popToRoot()
            } label: {
                Text("BackToC")
            }
        }
    }
}

这样所有的跳转其实都是在根类 B 和 C 中管理,避免了分散到每个页面的逻辑。同时可以方便返回到根视图。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-08-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 场景
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档