SwiftUI-如何将工具栏添加到导航视图中的TabView标签?

人气:687 发布:2022-10-16 标签: swiftui toolbar tabview navigationview

问题描述

我正在尝试将不同的toolbar添加到我的每个选项卡中,但它们没有显示。该应用程序将主要在横向iPad上使用,我可以将工具栏添加到TabView本身并显示它们,但我不知道如何将向下按下导航堆栈的按钮传递到要在本地处理的单个视图/视图模型。

我已尝试添加新的NavigationView%s(包括.stacknavigationViewStyle%s),但这仍然只是向视图中添加另一列。

这是一些基本的工作代码:

import SwiftUI

@main
struct NavTabTestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

struct ContentView: View {
    var body: some View {
            MasterView()
    }
}

struct MasterView: View {
    var body: some View {
        NavigationView {
            List {
                ForEach(0..<20) { index in
                    NavigationLink(
                        destination: DetailView(index: index)
                            .navigationTitle("Row (index)")
                    ) {
                        Text("(index) th row")
                    }.tag(index)
                }
            }.navigationTitle(Text("Ratty"))
        }
    }
}

struct DetailView: View {
    var index: Int
    
    @State var selectedTab = 1
    
    var body: some View {
        TabView(selection: $selectedTab) {
            Tab1(index: index).tabItem { Label("Tab1", systemImage: "list.dash") }
            Tab2(index: index).tabItem { Label("Tab2", systemImage: "aqi.medium") }
            Tab3(index: index).tabItem { Label("Tab3", systemImage: "move.3d") }
        }
    }
}

struct Tab1: View {    
    var index: Int
    
    var body: some View {
        Text("This is (index) in tab 1")
            .toolbar {
                ToolbarItem(placement: .primaryAction) {
                    Button("Bingo") { print("Bingo") }
                }
            }
    }
}

struct Tab2: View {
    var index: Int
    
    var body: some View {
        Text("This is (index) in tab 2")
            .toolbar {
                ToolbarItem(placement: .primaryAction) {
                    Button("Bongo") { print("Bongo") }
                }
            }
    }
}

struct Tab3: View {
    var index: Int
    
    var body: some View {
        Text("This is (index) in tab 3")
            .toolbar {
                ToolbarItem(placement: .primaryAction) {
                    Button("Banjo") { print("Banjo") }
                }
            }
    }
}

我开始怀疑这是否可能,以及是否只在每个选项卡顶部使用按钮实现我自己的视图会更好。

编辑:

推荐答案

您只需要使用一个级别NavigationView。换句话说,您不应该嵌套NavigationViews。看看这个答案。

Only Back Button Visible on Custom Navigation Bar SwiftUI

使用NavgationView作为您已使用的MasterView。 对每个Tab#视图使用NavigationView。 在MasterViewDetailsView之间切换。 在MasterView中使用Button而不是NavigationLink(您可以自定义它看起来像NavigationLink) 在每个Tab#视频中使用自定义后退按钮。

此选项控制应显示MasterViewDetailsView中的哪一个。

class BaseViewModel: ObservableObject {
    @Published var userFlow: UserFlow = .masterView
    
    init(){
        userFlow = .masterView
    }
    
    enum UserFlow {
        case masterView, detailsView
    }
}

此视图将在ContentView中使用或替代它。当您在MasterView中并单击列表行之一时,请设置appState.userFlow = .detailView。当您单击后退按钮时,设置appState.userFlow = .masterView

执行此操作时,您将在两个视图之间切换,并且一次显示一个NavigationView

到目前为止,它没有动画。如果您愿意,可以使用

https://developer.apple.com/tutorials/swiftui/animating-views-and-transitions

struct BaseView: View {
    
    @EnvironmentObject var appState: BaseViewModel
    
    @State var index: Int = 0
    
    var body: some View {
        Group {
            switch appState.userFlow {
            case .masterView:
                MasterView(index: $index)
            default:
                DetailView(index: index)
            }
        }
        .edgesIgnoringSafeArea(.bottom)
    }
}

完成代码

struct ContentView: View {
    var body: some View {
        BaseView().environmentObject(BaseViewModel())
    }
}


class BaseViewModel: ObservableObject {
    @Published var userFlow: UserFlow = .masterView
    
    init(){
        userFlow = .masterView
    }
    
    enum UserFlow {
        case masterView, detailsView
    }
}


struct BaseView: View {
    
    @EnvironmentObject var appState: BaseViewModel
    
    @State var index: Int = 0
    
    var body: some View {
        Group {
            switch appState.userFlow {
            case .masterView:
                MasterView(index: $index)
            default:
                DetailView(index: index)
            }
        }
        .edgesIgnoringSafeArea(.bottom)
    }
}


struct MasterView: View {
    @EnvironmentObject var appState: BaseViewModel
    
    @Binding var index: Int
    
    var body: some View {
        NavigationView {
            List {
                ForEach(0..<20) { index in
                    Button(action: {
                        appState.userFlow = .detailsView
                        $index.wrappedValue = index
                    }, label: {
                        HStack {
                            Text("(index) th row")
                            Spacer()
                            Image(systemName: "greaterthan")
                        }
                    })
                    .tag(index)
                }
            }.navigationTitle(Text("Ratty"))
        }
    }
}

struct DetailView: View {
    var index: Int
    
    @State var selectedTab = 1
    
    var body: some View {
        TabView(selection: $selectedTab) {
            Tab1(index: index).tabItem { Label("Tab1", systemImage: "list.dash") }
            Tab2(index: index).tabItem { Label("Tab2", systemImage: "aqi.medium") }
            Tab3(index: index).tabItem { Label("Tab3", systemImage: "move.3d") }
        }
    }
}

struct Tab1: View {
    @EnvironmentObject var appState: BaseViewModel
    
    var index: Int
    
    var body: some View {
        NavigationView {
            Text("This is (index) in tab 1")
                .toolbar {
                    ToolbarItem(placement: .navigationBarLeading) {
                        Button("back") { appState.userFlow = .masterView  }
                    }
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button("Bingo") { print("Bingo") }
                    }
                }
        }
    }
}

struct Tab2: View {
    @EnvironmentObject var appState: BaseViewModel
    
    var index: Int
    
    var body: some View {
        NavigationView {
            Text("This is (index) in tab 2")
                .toolbar {
                    ToolbarItem(placement: .navigationBarLeading) {
                        Button("back") { appState.userFlow = .masterView  }
                    }
                    ToolbarItem(placement: .primaryAction) {
                        Button("Bongo") { print("Bongo") }
                    }
                }
        }
    }
}

struct Tab3: View {
    @EnvironmentObject var appState: BaseViewModel
    var index: Int
    
    var body: some View {
        NavigationView {
            Text("This is (index) in tab 3")
                .toolbar {
                    ToolbarItem(placement: .navigationBarLeading) {
                        Button("back") { appState.userFlow = .masterView  }
                    }
                    ToolbarItem(placement: .primaryAction) {
                        Button("Banjo") { print("Banjo") }
                    }
                }
        }
    }
}

我已自定义xtwistedx%ssolution。

418