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

Flutter新手求助:复用自定义ListView.builder展示两类商品列表

解决Flutter生鲜电商列表组件复用问题

要让ProductsListView同时适配水果和蔬菜列表,核心是让组件摆脱对固定列表的依赖,通过统一数据模型和动态传入列表参数来实现复用,具体步骤如下:

1. 统一数据模型

原代码中Fruits和Vegetables类结构完全一致,只是属性命名不同,我们可以抽象成通用的Product类,简化数据结构:

import '../utilities/constants.dart';

class Product {
  final String? image;
  final String? name;
  final String? category;
  final String? price;

  Product({this.image, this.name, this.category, this.price});
}

// 水果列表
final Product bananas = Product(
  image: '${kFruitsImagesAsset}bananas.png',
  name: 'Bananas',
  category: 'Organic',
  price: '\$4.99',
);

final Product apples = Product(
  image: '${kFruitsImagesAsset}apples.png',
  name: 'Apples',
  category: 'Organic',
  price: '\$5.00',
);

final Product chikku = Product(
  image: '${kFruitsImagesAsset}chikku.png',
  name: 'Chikku',
  category: 'Organic',
  price: '\$9.00',
);

final Product peaches = Product(
  image: '${kFruitsImagesAsset}peaches.png',
  name: 'Peaches',
  category: 'Organic',
  price: '\$12.00',
);

List<Product> fruitsList = [bananas, apples, chikku, peaches];

// 蔬菜列表
final Product okra = Product(
  image: '${kVegetablesImagesAsset}okra.png',
  name: 'Okra',
  category: 'Organic',
  price: '\$6.99',
);

final Product peas = Product(
  image: '${kVegetablesImagesAsset}peas.png',
  name: 'Peas',
  category: 'Organic',
  price: '\$10.50',
);

final Product potatoes = Product(
  image: '${kVegetablesImagesAsset}potatoes.png',
  name: 'Potatoes',
  category: 'Organic',
  price: '\$5.99',
);

final Product taro = Product(
  image: '${kVegetablesImagesAsset}taro.png',
  name: 'Taro',
  category: 'Organic',
  price: '\$5.50',
);

List<Product> vegetablesList = [okra, peas, potatoes, taro];

2. 重构ProductsListView组件

移除原组件中无用的单个属性参数,改为接收一个List<Product>类型的列表,让组件动态渲染传入的列表数据:

import 'package:flutter/material.dart';
import 'package:grocery_store/models/products_list.dart';

import '../utilities/add_product.dart';
import '../utilities/constants.dart';

class ProductsListView extends StatelessWidget {
  // 新增:接收通用产品列表
  final List<Product> products;

  const ProductsListView({
    Key? key,
    required this.products, // 必须传入的参数
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      scrollDirection: Axis.horizontal,
      itemCount: products.length, // 使用传入列表的长度
      itemBuilder: (BuildContext context, int index) {
        final product = products[index];
        return ClipRect(
          child: Container(
            width: 140.0,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(15.0),
              color: Colors.white,
              boxShadow: const [
                BoxShadow(
                  blurRadius: 10,
                  color: Colors.black,
                ),
              ],
            ),
            margin: const EdgeInsets.all(10.0),
            child: Padding(
              padding: const EdgeInsets.fromLTRB(20, 10, 10, 10),
              child: Column(
                children: [
                  Image.asset(
                    product.image!,
                    height: 80.0,
                    width: 90.0,
                  ),
                  const SizedBox(
                    height: 15,
                  ),
                  Row(
                    children: [
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            product.name!,
                            style: const TextStyle(
                              fontSize: 15.0,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                          Text(
                            product.category!,
                            textAlign: TextAlign.left,
                            style: const TextStyle(
                              height: 1.5,
                              color: kDarkGrey,
                              fontSize: 12.5,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                  Row(
                    children: [
                      Text(
                        product.price!,
                        style: const TextStyle(
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      const Spacer(),
                      const AddProduct(),
                    ],
                  )
                ],
              ),
            ),
          ),
        );
      },
    );
  }
}

3. 更新首页调用

在GroceryPage中调用ProductsListView时,分别传入水果列表和蔬菜列表:

// ... 其余代码不变 ...
                Column(
                  children: [
                    const ProductCardsRow(
                      groceryType: 'Fruits',
                    ),
                    SizedBox(
                      height: 215,
                      width: double.infinity,
                      child: ProductsListView(
                        products: fruitsList, // 传入水果列表
                      ),
                    ),
                  ],
                ),
                Column(
                  children: [
                    const ProductCardsRow(
                      groceryType: 'Vegetables',
                    ),
                    SizedBox(
                      height: 215,
                      width: double.infinity,
                      child: ProductsListView(
                        products: vegetablesList, // 传入蔬菜列表
                      ),
                    ),
                  ],
                ),
// ... 其余代码不变 ...

这样修改后,ProductsListView就可以复用渲染任意符合Product模型的列表,不仅支持水果和蔬菜,后续新增其他品类也能直接复用该组件。

内容的提问来源于stack exchange,提问作者Ahmed Loutfy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 13:05:41