如何提取嵌套JSON对象的数据并填充到Flutter应用的ListView中
Flutter嵌套对象结构JSON转ListView实现方案
核心思路
你遇到的问题本质是接口用字符串为键的嵌套Map结构替代了常规数组,只需要把多层Map的value提取出来拍平为List,就可以复用你之前处理数组JSON的逻辑对接ListView。
步骤1:定义数据实体类
先创建分期数据对应的Dart模型,内置fromJson序列化方法:
class Installment { final int installment; final String link; final double amount; final double amountPaid; final String status; final String dueDate; final String receivableType; final String paymentMethod; final String acordo; final String createdAt; final String updatedAt; Installment({ required this.installment, required this.link, required this.amount, required this.amountPaid, required this.status, required this.dueDate, required this.receivableType, required this.paymentMethod, required this.acordo, required this.createdAt, required this.updatedAt, }); factory Installment.fromJson(Map<String, dynamic> json) { return Installment( installment: json['installment'], link: json['link'], amount: json['amount'], amountPaid: json['amount_paid'], status: json['status'], dueDate: json['due_date'], receivableType: json['receivable_type'], paymentMethod: json['payment_method'], acordo: json['acordo'], createdAt: json['created_at'], updatedAt: json['updated_at'], ); } }
步骤2:嵌套JSON解析逻辑
拿到接口返回的JSON数据后,通过遍历Map的value提取所有分期数据,转为List:
// 假设responseData是你请求接口拿到的Map<String, dynamic>类型数据 Map<String, dynamic> acordosMap = responseData['acordos']; List<Installment> installmentList = []; // 遍历第一层Map的所有value(示例中为key"29"对应的第二层Map) for (var secondLevelMap in acordosMap.values) { // 遍历第二层Map的所有value,就是我们需要的单条分期数据 for (var itemJson in secondLevelMap.values) { installmentList.add(Installment.fromJson(itemJson)); } }
该逻辑会自动收集acordos下所有层级的分期数据,不需要手动指定任何键名,适配动态key的场景
步骤3:对接ListView完整示例
import 'package:flutter/material.dart'; class InstallmentListPage extends StatefulWidget { const InstallmentListPage({super.key}); @override State<InstallmentListPage> createState() => _InstallmentListPageState(); } class _InstallmentListPageState extends State<InstallmentListPage> { List<Installment> installments = []; bool isLoading = true; @override void initState() { super.initState(); _loadInstallmentData(); } Future<void> _loadInstallmentData() async { // 此处替换为你的实际接口请求逻辑,示例为模拟返回数据 Map<String, dynamic> mockResponse = { "acordos": { "29": { "0": {"installment": 0, "link": "https://hml.use...", "amount": 55.07, "amount_paid": 0.0, "status": "VEN", "due_date": "2021-05-04", "receivable_type": "ACO", "payment_method": "banking_billet", "acordo": "86", "created_at": "2021-05-04", "updated_at": "2021-05-05"}, "1": {"installment": 1, "link": "https://hml.use...", "amount": 20.62, "amount_paid": 20.62, "status": "PAG", "due_date": "2021-05-04", "receivable_type": "ACO", "payment_method": "banking_billet", "acordo": "86", "created_at": "2021-05-04", "updated_at": "2021-05-04"}, "2": {"installment": 2, "link": "https://hml.use...", "amount": 20.62, "amount_paid": 20.62, "status": "PAG", "due_date": "2021-05-04", "receivable_type": "ACO", "payment_method": "banking_billet", "acordo": "86", "created_at": "2021-05-04", "updated_at": "2021-05-04"}, "3": {"installment": 3, "link": "https://hml.use...", "amount": 20.62, "amount_paid": 20.62, "status": "PAG", "due_date": "2021-05-04", "receivable_type": "ACO", "payment_method": "banking_billet", "acordo": "86", "created_at": "2021-05-04", "updated_at": "2021-05-04"}, } } }; // 执行JSON解析 Map<String, dynamic> acordosMap = mockResponse['acordos']; List<Installment> tempList = []; for (var secondLevelMap in acordosMap.values) { for (var itemJson in secondLevelMap.values) { tempList.add(Installment.fromJson(itemJson)); } } // 更新UI setState(() { installments = tempList; isLoading = false; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('分期列表')), body: isLoading ? const Center(child: CircularProgressIndicator()) : ListView.builder( itemCount: installments.length, itemBuilder: (context, index) { final item = installments[index]; return ListTile( title: Text('第${item.installment}期 ¥${item.amount.toStringAsFixed(2)}'), subtitle: Text('到期日:${item.dueDate} 支付方式:${item.paymentMethod == 'banking_billet' ? '银行卡' : '其他'}'), trailing: item.status == 'PAG' ? const Icon(Icons.check_circle, color: Colors.green, size: 20) : const Icon(Icons.schedule, color: Colors.orange, size: 20), ); }, ), ); } }
可选优化点
- 接口返回可能存在空值的场景下,解析前先对每层Map做判空处理,避免空指针异常
- 金额、日期可以通过
intl包格式化成本地化显示格式 - 状态字段可以做中文映射:PAG对应已支付、VEN对应待支付/已逾期
内容的提问来源于stack exchange,提问作者Acorcdev
相关产品推荐
相关产品推荐

