【问题标题】:SwiftUI, setting title to child views of TabView inside of NavigationView does not workSwiftUI,将标题设置为 NavigationView 内 TabView 的子视图不起作用
【发布时间】:2021-04-20 17:37:52
【问题描述】:

为什么我将 TabView 放入 NavigationView 是因为当用户进入具有自己的底部操作栏的第二级“详细”视图时,我需要隐藏底部标签栏。

但是这样做会导致另一个问题:TabView 托管的所有第一级“列表”视图不再显示它们的标题。下面是一个示例代码:

import SwiftUI

enum Gender: String {
    case female, male
}

let members: [Gender: [String]] = [
    Gender.female: ["Emma", "Olivia", "Ava"], Gender.male: ["Liam", "Noah", "William"]
]

struct TabItem: View {
    let image: String
    let label: String
    var body: some View {
        VStack {
            Image(systemName: image).imageScale(.large)
            Text(label)
        }
    }
}

struct ContentView: View {
    var body: some View {
        NavigationView {
            TabView {
                ListView(gender: .female).tag(0).tabItem {
                    TabItem(image: "person.crop.circle", label: Gender.female.rawValue)
                }
                ListView(gender: .male).tag(1).tabItem {
                    TabItem(image: "person.crop.circle.fill", label: Gender.male.rawValue)
                }
            }
        }
    }
}

struct ListView: View {
    let gender: Gender
    var body: some View {
        let names = members[gender]!
        return List {
            ForEach(0..<names.count, id: \.self) { index in
                NavigationLink(destination: DetailView(name: names[index])) {
                    Text(names[index])
                }
            }
        }.navigationBarTitle(Text(gender.rawValue), displayMode: .inline)
    }
}

struct DetailView: View {
    let name: String
    var body: some View {
        ZStack {
            VStack {
                Text("profile views")
            }
            VStack {
                Spacer()
                HStack {
                    Spacer()
                    TabItem(image: "pencil.circle", label: "Edit")
                    Spacer()
                    TabItem(image: "minus.circle", label: "Delete")
                    Spacer()
                }
            }
        }
        .navigationBarTitle(Text(name), displayMode: .inline)
    }
}

我可以做的是在根视图中有一个 @State var title 并将绑定传递给所有列表视图,然后让这些列表视图将其标题设置回根视图出现。但我只是觉得不太对劲,有没有更好的方法呢?感谢您的帮助。

【问题讨论】:

  • 我在here 中做了类似的事情,但是工作流中有一个 SwiftUI 内部崩溃。我观察到与您的代码快照相同的崩溃。请注意。
  • @Asperi,你是对的,模拟器在切换列表和关闭详细视图时会发出警告,但应用程序仍然存在并且正在运行。但是在真正的手机中它会崩溃..感谢您的提醒!你有没有想过如何摆脱这些错误?或任何动态隐藏选项卡视图的方法?
  • @Asperi,我猜标签视图阻碍了导航根视图及其子视图的连接,这就是为什么不能从子视图设置标题的原因,也是为什么子视图有无处可去。
  • 提供了我的方法

标签: swiftui


【解决方案1】:

这个想法是动态加入TabView 选择和NavigationView 内容。

演示:

这是描述方法的简化代码(使用您的视图)。 NavigationViewTabView 只是在ZStack 中独立定位,但NavigationView 的内容取决于TabView 的选择(内容只是存根),因此它们不会互相打扰。同样在这种情况下,可以根据某些条件隐藏/取消隐藏TabView - 在这种情况下,为简单起见,存在根列表视图。

struct TestTabsOverNavigation: View {

    @State private var tabVisible = true
    @State private var selectedTab: Int = 0
    var body: some View {
        ZStack(alignment: .bottom) {
            contentView
            tabBar
        }
    }

    var contentView: some View {
        NavigationView {
            ListView(gender: selectedTab == 0 ? .female : .male)
            .onAppear {
                withAnimation {
                    self.tabVisible = true
                }
            }
            .onDisappear {
                withAnimation {
                    self.tabVisible = false
                }
            }
        }
    }

    var tabBar: some View {
        TabView(selection: $selectedTab) {
            Rectangle().fill(Color.clear).tag(0).tabItem {
                TabItem(image: "person.crop.circle", label: Gender.female.rawValue)
            }
            Rectangle().fill(Color.clear).tag(1).tabItem {
                TabItem(image: "person.crop.circle.fill", label: Gender.male.rawValue)
            }
        }
        .frame(height: 50) // << !! might be platform dependent
        .opacity(tabVisible ? 1.0 : 0.0)
    }
}

【讨论】:

  • 大声笑,这正是我现在正在做的!刚刚卡在上面放双感叹号的地方,我正在尝试找到一种方法来从系统中获取标签栏默认高度而不是硬编码。
  • 它有不透明的背景,这就是我限制它的高度的原因。
  • 不透明的背景可能是唯一还不是 100% 完美的东西。选项卡视图的背景应该和导航栏一样,看起来和感觉有点模糊。您可以在该成员字典中添加 30 个以上的名称,并在列表视图中将 listRowBackground 设置为 Color.red,然后向下滚动一点以在导航栏下方创建列表项,以比较这两个视图的背景。我尝试将 TabView 移出 NavigationView 并直接按住列表视图,我可以看到两个背景相同,但是使用 ZStack 解决方案,选项卡视图背景是 100% 不透明的。
【解决方案2】:

这可能是一个迟到的答案,但 TabView 项目需要分配tag 编号否则绑定selection 参数将不会发生。以下是我如何在我的项目中做同样的事情:

@State private var selectedTab:Int = 0
private var pageTitles = ["Home", "Customers","Sales", "More"]
var body: some View {
    NavigationView{
        TabView(selection: $selectedTab, content:{
            HomeView()
                .tabItem {
                    Image(systemName: "house.fill")
                    Text(pageTitles[0])
                }.tag(0)
            CustomerListView()
                .tabItem {
                    Image(systemName: "rectangle.stack.person.crop.fill")
                    Text(pageTitles[1])
                }.tag(1)
            SaleView()
                .tabItem {
                    Image(systemName: "tag.fill")
                    Text(pageTitles[2])
                }.tag(2)
            
            MoreView()
                .tabItem {
                    Image(systemName: "ellipsis.circle.fill")
                    Text(pageTitles[3])
                }.tag(3)
        })
        .navigationBarTitle(Text(pageTitles[selectedTab]),displayMode:.inline)

        .font(.headline)
    }
}

【讨论】:

    猜你喜欢
    • 2019-12-11
    • 1970-01-01
    • 1970-01-01
    • 2020-06-22
    • 1970-01-01
    • 2021-06-14
    • 1970-01-01
    • 2020-11-06
    • 2021-08-01
    相关资源
    最近更新 更多