SwiftUI - 如何使用 ForEach 为 .tabItems 构建设置 .tag

问题描述 投票:0回答:1

在下面的示例代码中,希望它不要太长,我很难正确地完成它。起初,我确实想使用具有关联值和操作的枚举,但选择了一种我确实更好理解的方式。

在我当前的代码中,.tag 让我有点头疼,我确实尝试了几种方法来使其正确,但没有任何效果。它显示的错误是“.tag(item.tag)”行和“.tabItem”行上的“引用静态方法“buildExpression”时没有完全匹配”。

import SwiftUI

class SettingsTabItemManager: ObservableObject {
    @Published var tabItems: [SettingsTabItem] = []

    init() {
        createTabItems()
    }

    func createTabItems() {
        self.tabItems = [
             SettingsTabItem(
                label: "General",
                labelImage: "gear", 
                tag: "general", 
                action: {}, 
                view: GeneralSettingsView(), 
                description: "The general settings tabItem"),
                         
             SettingsTabItem(
                label: "Network", 
                labelImage: "network", 
                tag: "network", 
                action: {}, 
                view: NetworkSettingsView(), 
                description: "The network settings tabItem"),
                         
             SettingsTabItem(
                label: "Advanced", 
                labelImage: "star", 
                tag: "advanced", 
                action: {}, 
                view: AdvancedSettingsView(), 
                description: "The advanced settings tabItem")
        ]
    }
}

struct SettingsTabItem {
    var id : UUID = UUID()
    var label: String
    var labelImage: String
    var tag: String // or enum Tabs
    var action: () -> Void
    var view: any View
    var description: String
}

struct SettingsView: View {
    @StateObject private var tabItemManager = SettingsTabItemManager()
    @State private var selectedTab: String?

    init() {
        _selectedTab = State(initialValue: tabItemManager.tabItems.first?.tag)
    }


    @State var tapped = false

    var body: some View {
        TabView {
            Group {
                ForEach(tabItemManager.tabItems, id: \.id) { item in
                    item.view
                        .tabItem {
                            Label(item.label, systemImage: item.labelImage)
                        }
                        .tag(item.tag) // I did try also ( .tag(item.tag.hashValue) )
                }
                .onTapGesture {
                    tapped.toggle()
                    //  more is comming
                }
            }
            .padding(20)
            .frame(width: 375, height: 150)
        }
    }
}

struct GeneralSettingsView: View {
    var body: some View {
        Text("GeneralSettingsView")
    }
}

struct NetworkSettingsView: View {
    var body: some View {
        Text("NetworkSettingsView")
    }
}

struct AdvancedSettingsView: View {
    var body: some View {
        Text("AdvancedSettingsView")
    }
}

我在这里忽略了什么?也许我应该采取不同的做法,但这就是我想到的。也许我应该使用某种视图生成器,但不知道该怎么做。 预先感谢。

swift swiftui tabitem
1个回答
0
投票

您的

View
中不应有
SettingsTabItem

var view: any View // remove this!

我假设您希望能够动态更改选项卡视图中的选项卡,这就是您创建

SettingsTabItem
结构的原因。因此
SettingsTabItem
数组代表 state,SwiftUI 中的视图是状态的函数。

您应该编写一个函数,给定

SettingsTabItem
,返回一些
View
。例如,在您在这里展示的简单案例中:

@ViewBuilder
func tabView(forTabItem tabItem: SettingsTabItem) -> some View {
    switch tabItem.tag { // also consider using an enum for the tag
    case "general":
        GeneralSettingsView()
    case "network":
        NetworkSettingsView()
    case "advanced":
        AdvancedSettingsView()
    default:
        EmptyView()
    }
}

您可以扩展此函数来执行您需要执行的任何操作,以找出与给定

View
对应的
SettingsTabItem
应该是什么。在实际场景中,您可能需要向
SettingsTabItem
添加更多属性。

请注意,我通过使用

@ViewBuilder
避免了视图都具有不同类型的问题,并且只有在将视图编写为状态函数时才能做到这一点。您尝试使用
any View
来解决此问题,但这导致了错误。

然后你就可以在

ForEach
中调用这个函数了:

tabView(forTabItem: item)
    .tabItem {
        Label(item.label, systemImage: item.labelImage)
    }
    .tag(item.tag)
© www.soinside.com 2019 - 2024. All rights reserved.