背景
最近做 SwiftUI 项目,之前对于 navigationDestination 的用法理解不太深刻,觉得很是难用,最近发现了正确的使用方式,这里记录一下。
场景
假设有一个 TabView 类为 A,A 有 B、C 两个Tab,C 的 Tab 下子界面有 D,D 的子界面有 E。
即有 A -> B 和 A -> C -> D -> E 两条链路。
之前的用法是:
1 |
|
这里面简单的使用确实没问题,每个界面的返回可以通过 Environment 的dismiss 来实现。但是如果想要实现从 E 返回到 C 就非常麻烦了。而且,这里每一步的跳转都散落在各个类里,没有统一的地方管理,后续维护也不易。
所以针对上面存在的问题,对使用进行了优化,
- 针对TabView 的两个子视图,B 和 C,分别用
NavigationStack
包装。不要把NavigationStack
放在TabView
的外层,因为遇到了放在这里,针对navigationDestination做跳转的时候,遇到了跳转多次的问题。 - 声明一个
BNavCoordinator
和CNavCoordinator
,分别用于管理B
和C
的跳转。在具体的NavCoordinator
中,声明一个枚举管理这个页面下的所有子界面。然后创建NavCoordinator
,实现push
、pop
、popToRoot
和navigator
方法。
示例代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35enum CNavScreens: Hashable {
case d(param1: Int, param2: String)
case e
}
struct CNavCoordinator: ObservableObject {
var paths = NavigationPath()
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)
}
} - 然后在具体页面中使用,示例如下
1 |
|
这样所有的跳转其实都是在根类 B 和 C 中管理,避免了分散到每个页面的逻辑。同时可以方便返回到根视图。