You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI实现含图片与名称的单网格视图及导航栏标题传值

解决方案

方案一:统一数据结构(推荐)

先调整分类数据结构,让每个分类项同时包含名称和图片,确保两者一一对应:

struct ContentView: View {
    struct ProductTypes: Identifiable {
        let id: Int
        let name: String // 分类名称,与prodType的key一致
        let image: String // 对应图片名称
    }
    
    // 初始化分类数据,保证name与prodType的key匹配
    let typeItems = [
        ProductTypes(id: 1, name: "Bakery", image: "bakery"),
        ProductTypes(id: 2, name: "Dairy", image: "diary"),
        ProductTypes(id: 3, name: "Fruits", image: "fruits"),
        ProductTypes(id: 4, name: "Vegans", image: "vegans"),
        ProductTypes(id: 5, name: "Vegetables", image: "vegetables")
    ]
    
    @ObservedObject var groceryViewModel: ProductViewModel
    
    let columns: [GridItem] = Array(repeating: .init(.flexible()), count: 3)
    
    var body: some View {
        NavigationView {
            ScrollView {
                LazyVGrid(columns: columns, spacing: 12) {
                    ForEach(typeItems) { item in
                        NavigationLink(
                            // 传递分类名称到下一页
                            destination: ProductListView(groceryViewModel: groceryViewModel, categoryName: item.name),
                            label: {
                                // 单个网格项:图片在上,名称在下的垂直布局
                                VStack(spacing: 8) {
                                    Image(item.image)
                                        .resizable()
                                        .clipShape(Circle())
                                        .scaledToFill()
                                        .frame(width: 100, height: 100)
                                        .clipped() // 防止图片溢出圆形边界
                                    
                                    Text(item.name)
                                        .font(.system(.headline, weight: .bold))
                                        .foregroundColor(.black)
                                        .multilineTextAlignment(.center)
                                }
                                .padding(.vertical, 8)
                            }
                        )
                    }
                }
                .padding()
                .onAppear {
                    groceryViewModel.readJSONFile(filename: "Groceries")
                }
            }
            .navigationBarTitle("Categories", displayMode: .inline)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(groceryViewModel: ProductViewModel())
    }
}

方案二:通过名称匹配图片(无需修改原有数据结构)

如果不想调整ProductTypes结构,可直接遍历prodType的key,通过名称匹配对应图片(假设图片名称为分类名称的小写形式):

struct ContentView: View {
    struct ProductTypes: Identifiable {
        let id: Int
        let image: String
    }
    
    let typeImages = [ProductTypes(id: 1, image: "bakery"),ProductTypes(id: 2, image: "diary"),ProductTypes(id: 3, image: "fruits"),ProductTypes(id: 4, image: "vegans"),ProductTypes(id: 5, image: "vegetables")]
    
    @ObservedObject var groceryViewModel : ProductViewModel
    
    let columns : [GridItem] = Array(repeating: .init(.flexible()),count: 3)
    
    var body: some View {
        NavigationView {
            ScrollView{
                LazyVGrid(columns: columns,spacing: 12) {
                    ForEach(groceryViewModel.prodType.keys.sorted(),id: \.self) { categoryName in
                        // 根据分类名称匹配对应图片
                        let imageName = categoryName.lowercased()
                        NavigationLink(
                            destination: ProductListView(groceryViewModel: groceryViewModel, categoryName: categoryName),
                            label:{
                                VStack(spacing: 8) {
                                    Image(imageName)
                                        .resizable()
                                        .clipShape(Circle())
                                        .scaledToFill()
                                        .frame(width: 100,height: 100)
                                        .clipped()
                                    
                                    Text(categoryName)
                                        .font(.system(.headline,weight: .bold))
                                        .foregroundColor(.black)
                                        .multilineTextAlignment(.center)
                                }
                                .padding(.vertical, 8)
                            }
                        )
                    }
                }
                .padding()
                .onAppear {
                    groceryViewModel.readJSONFile(filename: "Groceries")
                }
            }
            .navigationBarTitle("Categories",displayMode: .inline)
        }
    }
}

struct ContentView_Previews : PreviewProvider {
    static var previews: some View{
        ContentView( groceryViewModel: ProductViewModel())
    }
}

下一页(ProductListView)适配修改

无论采用哪种方案,都需要在ProductListView中接收分类名称并设置为导航标题:

struct ProductListView: View {
    @ObservedObject var groceryViewModel: ProductViewModel
    let categoryName: String // 接收传递的分类名称
    
    var body: some View {
        // 此处替换为你的产品列表内容
        Text("Products in \(categoryName)")
            .navigationBarTitle(categoryName, displayMode: .inline) // 设置导航栏标题为分类名称
    }
}

核心修改说明

  • 合并两个独立的ForEach循环,让每个网格项同时包含图片和对应分类名称
  • 通过NavigationLink的destination参数将分类名称传递到下一页
  • 在目标页面直接使用接收的名称设置导航栏标题

内容的提问来源于stack exchange,提问作者Vinduja Narayanan K

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 16:24:59