Flutter技术问题:如何根据product_key从对象模型提取对应Map
问题:根据product_key提取对应Map并生成Flutter Widget列表
一、初始场景与疑问
我有一个返回List<GoodsModel>格式数据的模型,示例数据如下:
[ GoodsModel(id: 483, productCategory: sport, productType: t-shirt, productDisplayName: Shirt, product_key: sport_goods, productRecommendation: null, sport_goods: {id: 12, name: t-shirt colored, color: blue}) ]
其中product_key的值(如sport_goods)与对应的Map键名完全一致。我想根据product_key提取对应的Map(比如示例中的sport_goods),写了初始代码但不确定return部分如何编写:
var myMap = goodsList.map((e) { if (e.product_key == 'sport_goods') { return ???; } });
二、Flutter代码问题(生成Widget列表)
我的最终目标是基于提取出的Map生成Widget列表,尝试编写的代码存在问题,希望得到解决:
import 'package:flutter/material.dart'; class GoodsList extends StatefulWidget { const GoodsList({super.key}); @override State<GoodsList> createState() => _GoodsListState(); } class _GoodsListState extends State<GoodsList> { // Data sample var data = { "id": 483, "productCategory": "sport", "productType": "t-shirt", "productDisplayName": "Shirt", "product_key": "sport_goods", // (2) based on this value "productRecommendation": null, // (1) I need to get this data "sport_goods": { "id": 12, "name": "t-shirt colored", "color": "blue", } }; @override Widget build(BuildContext context) { for (var i = 0; i < data.length; i++) { // (3) how to get the piece of map in here??? if (data[i]!['product_key'] == 'sport_goods') { return Column( children: [ Text(data[i]!['sport_goods']!['id']), Text(data[i]!['sport_goods']!['name']), Text(data[i]!['sport_goods']!['color']), ], ) // This is the problem I believe } } return const Text('No data'); } }
解决方案
一、从GoodsModel中提取对应Map
方法1:添加模型方法(推荐,无反射)
在GoodsModel类中新增一个方法,直接根据product_key返回对应的Map:
class GoodsModel { // 原有的字段和构造方法 final int id; final String productCategory; final String productType; final String productDisplayName; final String product_key; final Map<String, dynamic>? sport_goods; // 其他可能的商品类型Map字段 GoodsModel({ required this.id, required this.productCategory, required this.productType, required this.productDisplayName, required this.product_key, this.sport_goods, // 其他字段的构造参数 }); // 新增方法:获取对应商品详情Map Map<String, dynamic>? getProductMap() { switch(product_key) { case 'sport_goods': return sport_goods; // 如果有其他product_key类型,添加对应的case default: return null; } } }
之后你的初始代码可以这样写:
// 过滤并提取符合条件的Map,移除null值 var myMapList = goodsList .map((e) => e.getProductMap()) .whereType<Map<String, dynamic>>() .toList();
方法2:通过toJson转换(动态适配多类型)
如果GoodsModel有toJson方法(通常由json_serializable生成),可以转成Map后通过product_key动态取值:
var myMapList = goodsList.map((e) { if (e.product_key == 'sport_goods') { final modelMap = e.toJson(); return modelMap[e.product_key] as Map<String, dynamic>?; } return null; }).whereType<Map<String, dynamic>>().toList();
二、修正Flutter代码生成Widget列表
你的原有代码存在3个核心问题:
data是单个Map而非List,无法通过索引遍历多个商品- build方法中循环直接return会终止渲染,只能返回第一个匹配项
- Text组件接收的数字类型未转成字符串
修正后的完整代码:
import 'package:flutter/material.dart'; class GoodsList extends StatefulWidget { const GoodsList({super.key}); @override State<GoodsList> createState() => _GoodsListState(); } class _GoodsListState extends State<GoodsList> { // 修正为List存储多商品数据 List<Map<String, dynamic>> data = [ { "id": 483, "productCategory": "sport", "productType": "t-shirt", "productDisplayName": "Shirt", "product_key": "sport_goods", "productRecommendation": null, "sport_goods": { "id": 12, "name": "t-shirt colored", "color": "blue", } }, // 可以添加更多商品数据 ]; @override Widget build(BuildContext context) { // 过滤符合条件的商品,并提取对应的详情Map final validProductMaps = data .where((item) => item['product_key'] == 'sport_goods') .map((item) { // 动态根据product_key提取对应Map return item[item['product_key']] as Map<String, dynamic>; }) .toList(); if (validProductMaps.isEmpty) { return const Center(child: Text('No data')); } // 生成Widget列表(用ListView避免溢出) return ListView.builder( padding: const EdgeInsets.all(16), itemCount: validProductMaps.length, itemBuilder: (context, index) { final product = validProductMaps[index]; return Card( margin: const EdgeInsets.only(bottom: 12), child: Padding( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('ID: ${product['id']}'), const SizedBox(height: 4), Text('名称: ${product['name']}'), const SizedBox(height: 4), Text('颜色: ${product['color']}'), ], ), ), ); }, ); } }
关键优化点说明:
- 将
data改为List<Map<String, dynamic>>,支持多商品数据 - 先过滤并提取目标Map,再通过
ListView.builder生成列表,避免单次return终止渲染 - 动态使用
item[item['product_key']]获取对应Map,无需硬编码键名 - 将数字类型的
id转为字符串后传入Text组件,避免类型错误 - 使用Card和Padding优化UI布局,提升可读性
内容的提问来源于stack exchange,提问作者kalibear
相关产品推荐
相关产品推荐

