NavigationStack 与 TabView 结合(SwiftUI、iOS16)

Luk*_*kas 5 swiftui swiftui-tabview ios16 swiftui-navigationstack

结合上述观点的正确方法是什么?

截至目前,NavigationStack我的应用程序底部有一个。它显示 aLaunchView作为 root。当用户通过身份验证时,主视图将添加到堆栈中,如果没有,登录/注册视图将添加到堆栈中。这很好用。

NavigationStack(path: self.$vm.path) {
        LaunchView()
            .navigationDestination(for: Authentication.self) { value in
                switch value {
                    case .login:
                        LoginView(vm: LoginViewModel() { type, action in
                            ...
                        })
                    case .verify: // let .verify(email)
                        VerifyMailView(vm: VerifyMailViewModel() { type, action in
                            ...
                        })
                    case .authenticated:
                        AuthenticatedView() { type, action in
                            self.vm.set(type: type) { value in
                                ...
                            }
                        }
                }
            }
        
    }
Run Code Online (Sandbox Code Playgroud)

AuthenticatedView由一个具有三个视图的视图组成TabView。问题来了。我以为我可以直接在它们上设置三个视图的标题和工具栏,但事实并非如此。但是,我不想也不能在选项卡视图中设置标题或工具栏,因为它们需要来自视图视图模型的数据(拥有TabView且不应该拥有访问权限)。

TabView(selection: self.$vm.index) {
        DiscoverView(vm: DiscoverViewModel(account: self.vm.$account, type: self.type))
        .tabItem {
            Image(self.vm.index == 0 ? "discover.selected" : "discover")
        }
        .tag(0)
        
        MatchesView(vm: MatchesViewModel(type: self.type))
        .tabItem {
            Image(self.vm.index == 1 ? "matches.selected" : "matches")
        }
        .tag(1)
        
        ProfileView(vm: ProfileViewModel(account: self.vm.$account, type: self.type))
        .tabItem {
            Image(self.vm.index == 2 ? "profile.selected" : "profile")
        }
        .tag(2)
    }
    .toolbar(.hidden, for: .navigationBar)
Run Code Online (Sandbox Code Playgroud)

我发现的唯一解决方法是隐藏导航栏并在子视图中TabView设置新的。NavigationView

        NavigationView {
            VStack {
                ...
            }
            .navigationTitle(Text("discover"))
            .toolbar {
                ...
            }
        }
Run Code Online (Sandbox Code Playgroud)

然而,这感觉不正确,因为它是一个 NavigationView 内的一个 NavigationView,甚至是有问题的(标题和工具栏有时放置在其正常位置下方,有点像隐藏但仍然存在的导航栏下方)TabView

因此,有没有人找到如何正确组合 aNavigationStack和 a的解决方案TabView

Fra*_*une 4

我发现lorem ipsum的评论很有启发性,因此我根据他们的想法构建了一个示例应用程序。

以下 Swift 代码是如何构建基本应用程序的示例,其中 TabView 中的每个页面都有自己的 NavigationStack。

import SwiftUI

struct ContentView: View {
    var body: some View {
        TabView {
            AirplaneView()
                .tabItem {
                    Label("Airplane Tab", systemImage: "airplane.circle")
                }
            PlanetView()
                .tabItem {
                    Label("Planet Tab", systemImage: "globe.americas.fill")
                }
        }
    }
}

struct AirplaneView: View {
    var body: some View {
        NavigationStack {
            VStack {
                Text("Airplane tab view")
                Divider()
                NavigationLink(destination: NestedItemA()) {
                    Text("Go to nested airplane view")
                }
                .navigationTitle("Airplane")
            }
        }
    }
}

struct PlanetView: View {
    var body: some View {
        NavigationStack {
            VStack {
                Text("Planet tab view")
                Divider()
                NavigationLink(destination: NestedItemB()) {
                    Text("Go to nested planet view")
                }
                .navigationTitle("Planet")
            }
        }
    }
}

struct NestedItemA: View {
    var body: some View {
        NavigationStack {
            Text("Airplane goes vroom")
                .navigationTitle("Nested airplane")
        }
    }
}

struct NestedItemB: View {
    var body: some View {
        NavigationStack {
            Text("Planet spin good")
                .navigationTitle("Nested planet")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是动画预览。