【问题标题】:SwiftUI - How to add toolbars to TabView tabs inside a NavigationView?SwiftUI - 如何将工具栏添加到 NavigationView 内的 TabView 选项卡?
【发布时间】:2021-09-13 10:58:26
【问题描述】:

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

我尝试添加新的NavigationViews(包括.stacknavigationViewStyles),但这仍然只是在视图中添加了另一列。

这是一些准系统,工作代码:

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 应该是 TabView 的子项,而不是您所做的其他方式。导航到 DetailsView 是否重要?您可以呈现它并为每个选项卡视图添加一个 NavgationView?
  • @mahan - 我尝试将 NavigationView 移动到 List 中,但我的视图变得毫无意义。我不明白我可以把它放在哪里。另外,我没有绑定到 NavigationLink,但是当从列表中选择某些内容时,我将如何填充 Detail 视图?

标签: swiftui toolbar navigationview tabview


【解决方案1】:

不确定这是否有帮助,但它确实通过导航视图中的工具栏回顾了一些有趣的概念。

链接:Stewart Lynch

【讨论】:

  • 谢谢。有趣的东西,但我认为我的问题与 TabViews 处理/继承 NavigationViews 的特定方式有关。
【解决方案2】:

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

Only Back Button Visible on Custom Navigation Bar SwiftUI


  1. NavgationView 用作您所使用的MasterView
  2. 为每个Tab# 视图使用NavigationView
  3. MasterViewDetailsView 之间切换。
  4. MasterView 中使用Button 而不是NavigationLink(您可以将其自定义为NavigationLink
  5. 在每个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") }
                    }
                }
        }
    }
}


我已经自定义了xtwistedxsolution

【讨论】:

  • 谢谢!这看起来很有希望,我明天会完成它。但是,不同的工具栏出现在主(列表)视图中,而不是单个详细信息/选项卡视图中。我会看看我是否可以使用你的代码来实现这一点,然后我会相信你的回答。
  • 不,工具栏已附加到选项卡视图。 @Magnas
  • 是的,工具栏附加到代码中的选项卡视图,但工具栏附加到主(左)视图,我希望不同的工具栏附加到细节(右)意见。请查看我对问题的编辑。
  • @Magnas 选项卡视图是否有导航项(标题、按钮等)?