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
相关产品推荐
相关产品推荐

