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

Flutter中如何从列表内的Map获取键值并在ListView展示

问题:如何将API返回的Map键值存入List并在ListView中展示

我在API调用中尝试把返回的Map的键和值存入List<Presence>,希望在ListView的Text组件里访问并展示这些键值,但目前实现有问题。以下是我的相关代码:

API请求代码

Future<List<Presence>> getPresencesByAthleteId(
      int depId, int teamId, int? id, context)  async {
        try {
          final response = await http.get(
              Uri.parse(
                  '$uri/get-presences-by-athlete-id?depId=$depId&teamId=$teamId&id=$id'),
              headers: {
                'Authorization': 'Basic ...',
                'Content-Type': 'application/json',
                'Accept': 'application/json'
              });
          print('Response status: ${response.statusCode}');
          print('Response body: ${response.body}');
    
          if (response.statusCode == 200) {
            if (response.body.isNotEmpty) {
              print('response.body.isNotEmpty');
              Map map = json.decode(response.body);
              List<Presence>? presencesList = [];
              map.forEach((key, value) {
                presencesList.add(Presence(
                    date: map.entries.first.key, count: map.entries.first.value));
                print('$key,$value');
              });
              return presencesList.toList();
            } else if (response.body.isEmpty) {
              print('response.body.isEmpty');
            }
          }
        } catch (e) {
          logger.e(e.toString());
        }
        return getPresencesByAthleteId(depId, teamId, id, context);
      }

ListView代码

child: FutureBuilder<List<Presence>>(
                    future: getPresencesByAthleteId(_athlete[i].department!.id, widget._team.teamKey!.teamId, _athlete[i].id, context),
                    builder: (BuildContext context, AsyncSnapshot snapshot) {
                      if (snapshot.hasData) {
                        return ListView.builder(
                            shrinkWrap: true,
                            primary: true,
                            physics: const ClampingScrollPhysics(),
                            scrollDirection: Axis.horizontal,
                            cacheExtent: 34,
                            itemCount: snapshot.data.length,
                            itemBuilder: (BuildContext context, int index) {
                              return ListTile(
                                title: Column(
                                  mainAxisSize: MainAxisSize.min,
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    Row(
                                      children: [
                                        Text('${(index + 1).toString()}.'),
                                        const SizedBox(
                                          width: 5,
                                        ),
                                        Text(snapshot.data[index].toString()),
                                        const SizedBox(
                                          width: 20,
                                        ),
                                        Text(
                                          '{presencesList[index]',
                                          style: const TextStyle(color: Colors.blue),
                                        )
                                      ],
                                    )
                                  ],
                                ),
                              );
                            });
                      } else if (snapshot.hasError) {
                        logger.e('${snapshot.error}');
                      }
                      return const Center(
                        heightFactor: 20,
                        child: CircularProgressIndicator.adaptive(),
                      );
                    })

Presence模型代码

class Presence {
  String date;
  int count;

  Presence({required this.date, required this.count});
  factory Presence.fromJson(Map<String, dynamic> json) => Presence(
        date: json['date'],
        count: json['count'] as int,
      );

  Map<String, dynamic> toJson() => {
        "date": date,
        "count": count,
      };
}

Postman返回的Map格式数据

{
"10-11-2022":1,
"9-11-2022":4,
"7-11-2022":1
}

解决方案

你的代码存在两处关键问题,修正后即可正常展示:

1. 修正API请求中Map转List的逻辑

当前循环中每次都添加map.entries.first的键值,导致所有Presence对象都是同一个日期和计数。应该直接使用循环中的key和value:

map.forEach((key, value) {
  presencesList.add(Presence(date: key.toString(), count: value as int));
  print('$key,$value');
});

2. 修正ListView中展示Presence数据的逻辑

当前Text组件的写法错误,需要直接访问Presence对象的date和count属性,而不是调用toString()或者使用未定义的presencesList:

itemBuilder: (BuildContext context, int index) {
  final presence = snapshot.data[index];
  return ListTile(
    title: Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          children: [
            Text('${(index + 1).toString()}.'),
            const SizedBox(width: 5),
            Text('日期: ${presence.date}'),
            const SizedBox(width: 10),
            Text('计数: ${presence.count}', style: const TextStyle(color: Colors.blue)),
          ],
        )
      ],
    ),
  );
}

额外优化建议

  • 避免在FutureBuilder中直接调用API方法,建议将请求结果存入State变量,防止重复发起请求;
  • 处理response.body.isEmpty时返回空列表,避免后续逻辑报错:
    } else if (response.body.isEmpty) {
      print('response.body.isEmpty');
      return [];
    }
    
  • 递归调用getPresencesByAthleteId可能导致无限循环,建议替换为有限次数的重试逻辑或返回空列表。

内容的提问来源于stack exchange,提问作者kate_3dev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 03:35:19