我环顾四周,但没有看到任何这方面的信息。如果我想在 SwiftUI 中拥有多个导航堆栈,并拥有多个添加到不同导航堆栈的导航链接,我该怎么做?在我的用例中,我使用选项卡视图,所以我会是这样的:
NavigationStack(path: $globalNavigationStack) {
TabView {
PrimaryView()
SecondaryView()
}
}
然后也许在 PrimaryView 中:
struct PrimaryView: View {
var body: some View {
NavigationStack(path: $localNavigationStack) {
NavigationLink(value: SomeType.self) {
Button("This should add to local stack")
}
.navigationDestination(for: SomeType.val) { someType in
ViewOnLocalStack()
}
NavigationLink(value: SomeType.self) {
Button("This should add to global stack")
}
.navigationDestination(for: SomeType.val) { someType in
ViewOnGlobalStack()
}
}
}
}
但是第二个
NavigationLink
将添加到本地堆栈中。假设我有权访问全局路径,如何使第二个路径添加到全局路径?我尝试的是这样的:
NavigationStack(path: $globalNavigationStack) {
TabView {
PrimaryView()
SecondaryView()
}
}
.navigationDestination(for: SomeType.val) { someType in
ViewOnGlobalStack()
}
同时从第二个链接中删除
onDestination
,但控制台抱怨导航链接没有相应的onDestination
。不知道是否见过其他人有类似的情况。
TLDR; 嵌套
NavigationStack
是不可能的。您将需要一种混合方法。以下答案是关于如何在不可能嵌套的情况下处理它的建议。
如果你尝试的话,XCode 不一定会抱怨。但即使你能够让它工作,你的应用程序也会很快崩溃。
我的建议:不要尝试破解它。
NavigationStack
能够很好地管理一层深度的导航状态。要在视图状态中创建细微差别,您要么必须创建大量具有隔离状态的视图,要么创建较少的具有共享状态的稳健视图。
这是树结构中不好的方法与一些建议的方法。请注意,我使用术语“屏幕”,因为视图在 SwiftUI 中具有特定含义。
您目前如何想象您的应用程序导航方案:
App <- NavigationStack
│
├── Screen1 <- NavigationStack
│ ├── Subscreen1A
│ └── Subscreen1B
│
└── Screen2 <- NavigationStack
├── Subscreen2A
└── Subscreen2B
App <- NavigationStack and global state object for subviews.
│
├── Screen1 <- reacts to global state object for changes
├── Screen2 <- reacts to global state object for changes
App <- NavigationStack
│
├── Screen1 <- custom state object with conditionally rendered subviews
├── Screen2 <- custom state object with conditionally rendered subviews
因此,我将记录有关如何处理子视图的几点指导:
NavigationStack
之外,使用这些数据类型来确定如何渲染整个视图或部分视图。最后,这里有一个例子来说明我之前提到的“更好的方法”。它会让你开始假设全局状态现在有效。
import SwiftUI
enum AppRoute: Hashable {
case screenOne
case screenTwo
case screenThree
}
final class AppState: ObservableObject {
@Published var path = NavigationPath()
// Can't be optional.
// Manage in parent to inject state into "child" views
@Published var screenTwoData = ?
@Published var isScreenTwoFlowActive: Bool = false
}
@main
struct MyApp: App {
@StateObject private var appState = AppState()
var body: some Scene {
WindowGroup {
NavigationStack(path: $appState.path) {
VStack {
ScreenOne()
}
.navigationDestination(for: AppRoute.self) { appRoute in
switch appRoute {
case .screenOne:
ScreenTwo()
case .screenTwo:
ScreenThree()
}
}
}
.environmentObject(appState)
}
}
}