如何使用ListView.builder实现从API获取的嵌套商品列表?
使用ListView.builder展示嵌套菜品列表
1. 数据处理
先把API返回的JSON转换为Dart可处理的结构,推荐用模型类保证类型安全:
定义Product模型类
class Product { final String productName; Product({required this.productName}); // 从JSON解析为Product对象 factory Product.fromJson(Map<String, dynamic> json) { return Product( productName: json["productName"].trim(), // 去除名称首尾冗余空格 ); } }
解析API返回的嵌套列表
// 假设API返回的原始JSON数据 final rawData = [ [{"productName": "Chicken Biryani Half"}, {"productName": " Chicken Momos"}], [{"productName": "Chicken Biryani Half"}, {"productName": "Chicken Biryani Half"}, {"productName": " Chicken Momos"}] ]; // 转换为强类型嵌套列表 final List<List<Product>> groupedProducts = rawData .map((group) => group.map((item) => Product.fromJson(item)).toList()) .toList();
2. 用嵌套ListView.builder构建UI
通过两层ListView.builder实现嵌套展示:外层处理分组,内层处理每组内的菜品:
ListView.builder( // 外层列表条目数等于分组数量 itemCount: groupedProducts.length, itemBuilder: (context, groupIndex) { final currentGroup = groupedProducts[groupIndex]; return Card( margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 分组标题(可选,用于区分不同餐组/订单) Text( "餐组 ${groupIndex + 1}", style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 12), // 内层ListView展示当前分组的菜品 ListView.builder( // 关键:让内层ListView仅占用所需空间 shrinkWrap: true, // 禁用内层滚动,避免与外层滚动冲突 physics: const NeverScrollableScrollPhysics(), itemCount: currentGroup.length, itemBuilder: (context, productIndex) { final product = currentGroup[productIndex]; return ListTile( leading: const Icon(Icons.fastfood), title: Text(product.productName), ); }, ), ], ), ), ); }, )
关键注意点
shrinkWrap: true:必须给内层ListView设置该属性,否则它会试图占用无限高度,引发布局错误。NeverScrollableScrollPhysics():禁用内层ListView的滚动能力,避免和外层ListView的滚动行为冲突。- 类型安全:用模型类替代直接操作
Map,可避免运行时类型错误,同时提升代码可维护性。
内容的提问来源于stack exchange,提问作者Prasenjit Das
相关产品推荐
相关产品推荐

