Flutter中解析自定义JSON并绑定到ListView.builder的实现方法
解决Dart中模拟JSON数据绑定到ListView.builder的问题
问题描述
我想在ListView.builder中展示分类数据,不想从API获取,所以自定义了模拟JSON数据:
final category = { "Table": "Category", "Result": [ {"Name": "Pants", "id": 1, "image": "cat1.png"}, {"Name": "T Shirts", "id": 2, "image": "cat2.png"}, {"Name": "Watches", "id": 3, "image": "cat3.png"} ] };
同时创建了两个实体类:
class CategoryList { String table; ResultCategory result; CategoryList(this.table, this.result); } class ResultCategory { String name; String id; String image; ResultCategory(this.name, this.id, this.image); }
尝试写了_getCategory方法但不知道怎么绑定到ListView.builder,现有方法代码:
Future<List<CategoryList>> _getCategory() async { final category = { "Table": "Category", "Result": [ {"Name": "Pants", "id": 1, "image": "cat1.png"}, {"Name": "T Shirts", "id": 2, "image": "cat2.png"}, {"Name": "Watches", "id": 3, "image": "cat3.png"} ] }; Map<String, dynamic> caregoryRes = json.decode(category); List<CategoryList> categorys = []; CategoryList categoryList = CategoryList(category.Table, category["Result"]); categorys.add(categoryList); return categorys; }
问题分析
- 实体类定义错误:
CategoryList中的result应为List<ResultCategory>类型,因为JSON里的Result是数组而非单个对象 - 无需调用
json.decode:category本身就是Dart的Map对象,不是JSON字符串,直接使用即可 - 实体类缺少Map转实体的构造方法,无法将模拟数据转换为实体对象
_getCategory返回值设计不合理,实际需要的是分类列表(List<ResultCategory>),而非包含单个CategoryList的列表
修正后的代码
1. 修正实体类
class CategoryList { String table; List<ResultCategory> result; CategoryList(this.table, this.result); // 从Map转换为实体的构造方法 CategoryList.fromMap(Map<String, dynamic> map) : table = map["Table"], result = (map["Result"] as List) .map((item) => ResultCategory.fromMap(item)) .toList(); } class ResultCategory { String name; String id; String image; ResultCategory(this.name, this.id, this.image); // 从Map转换为实体的构造方法 ResultCategory.fromMap(Map<String, dynamic> map) : name = map["Name"], id = map["id"].toString(), // 原数据id为int类型,转为String匹配实体类定义 image = map["image"]; }
2. 修正数据获取方法
模拟数据无需异步操作,可直接同步返回;若要模拟API请求的异步效果,也可保留Future格式:
// 同步获取数据(更简洁) List<ResultCategory> getCategoryItems() { final category = { "Table": "Category", "Result": [ {"Name": "Pants", "id": 1, "image": "cat1.png"}, {"Name": "T Shirts", "id": 2, "image": "cat2.png"}, {"Name": "Watches", "id": 3, "image": "cat3.png"} ] }; final categoryList = CategoryList.fromMap(category); return categoryList.result; } // 模拟异步请求(可选) Future<List<ResultCategory>> _getCategory() async { // 模拟网络延迟 await Future.delayed(const Duration(milliseconds: 500)); final category = { "Table": "Category", "Result": [ {"Name": "Pants", "id": 1, "image": "cat1.png"}, {"Name": "T Shirts", "id": 2, "image": "cat2.png"}, {"Name": "Watches", "id": 3, "image": "cat3.png"} ] }; final categoryList = CategoryList.fromMap(category); return categoryList.result; }
3. 绑定到ListView.builder
方式1:直接使用同步数据
ListView.builder( itemCount: getCategoryItems().length, itemBuilder: (context, index) { final item = getCategoryItems()[index]; return ListTile( leading: Image.asset(item.image), // 需在pubspec.yaml中配置本地图片路径 title: Text(item.name), subtitle: Text(item.id), ); }, )
方式2:用FutureBuilder处理异步数据
FutureBuilder<List<ResultCategory>>( future: _getCategory(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center(child: Text('加载失败: ${snapshot.error}')); } else if (!snapshot.hasData || snapshot.data!.isEmpty) { return const Center(child: Text('暂无分类数据')); } else { return ListView.builder( itemCount: snapshot.data!.length, itemBuilder: (context, index) { final item = snapshot.data![index]; return ListTile( leading: Image.asset(item.image), title: Text(item.name), subtitle: Text(item.id), ); }, ); } }, )
注意事项
若使用本地图片,需在pubspec.yaml中配置assets路径:
flutter: assets: - assets/cat1.png - assets/cat2.png - assets/cat3.png
如果是网络图片,将Image.asset替换为Image.network(item.image)即可。
内容的提问来源于stack exchange,提问作者Muhammed Javad
相关产品推荐
相关产品推荐

