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

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;
  }

问题分析

  1. 实体类定义错误:CategoryList中的result应为List<ResultCategory>类型,因为JSON里的Result是数组而非单个对象
  2. 无需调用json.decode:category本身就是Dart的Map对象,不是JSON字符串,直接使用即可
  3. 实体类缺少Map转实体的构造方法,无法将模拟数据转换为实体对象
  4. _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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 13:55:20