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

如何提取嵌套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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 02:06:03