在Flutter的FlCharts中绘制多维数组数据遇迭代问题求助
问题:FlCharts中遍历二级数组绘制折线图失败
我尝试将从API获取的数组数据在FlCharts中绘制,但无法正确遍历二级数组,以下是详细情况:
测试数据
var listData = [ { 'Product01': [12.0, 14.5, 15.6, 12.1, 15.2, 17.6, 12.8, 24.0, 35.4, 12.9] }, { 'Product02': [9.0, 12.5, 11.6, 7.1, 10.2, 14.6, 8.8, 18.0, 31.4, 10.9] }, ];
第一次尝试代码
var sections = listData.asMap().entries.map((data) { final idx = data.key; final listval = data.value; return LineChartBarData( spots: listval.asMap().entries.map((item) { FlSpot(item.key, item.val); }).toList(), color: chartColors[idx], barWidth: 5, isCurved: true, dotData: FlDotData(show: true), ); }).toList();
错误信息
lib/modules/home/widgets/yearly_expenses.dart:106:24: Error: The method 'asMap' isn't defined for the class 'Map<String, List<double>>'. - 'Map' is from 'dart:core'. - 'List' is from 'dart:core'. Try correcting the name to the name of an existing method, or defining a method named 'asMap'. spots: listval.asMap().entries.map((item) { ^^^^^
第二次修改代码
List sections = listData.asMap().entries.map((data) { final idx = data.key; final listval = data.value; listval.entries.map((entry) { final k = entry.key; final v = entry.value; return LineChartBarData( spots: v.asMap().entries.map((data) { return FlSpot(data.key, data.value); }).toList(), color: chartColors[idx], barWidth: 5, isCurved: true, dotData: FlDotData(show: true), ); }).toList(); }).toList();
错误信息
Error: The argument type 'List<dynamic>' can't be assigned to the parameter type 'List<LineChartBarData>'. - 'List' is from 'dart:core'. - 'LineChartBarData' is from 'package:fl_chart/src/chart/line_chart/line_chart_data.dart' ('.pub-cache/hosted/pub.dev/fl_chart-0.69.0/lib/src/chart/line_chart/line_chart_data.dart'). lineBarsData: sections, ^
我可以完全控制API的数组结构,也请建议是否需要优化数组格式。
解决方案
代码修正
两次错误的核心原因:
- 第一次错误:
listval是Map类型,不能调用仅属于List的asMap()方法;同时内部的map回调漏写了return,导致spots列表元素为null。 - 第二次错误:外层
map回调没有返回内部listval.entries.map()生成的结果,且未指定sections的具体类型,导致类型不匹配。
修正后的代码:
// 明确指定类型,避免dynamic类型问题 List<LineChartBarData> sections = listData.asMap().entries.map((data) { final idx = data.key; final mapItem = data.value; // 取出Map中唯一的List数据(每个元素仅含一个键值对) final values = mapItem.values.first; return LineChartBarData( spots: values.asMap().entries.map((entry) { // 注意返回FlSpot,且将x轴的int转为double return FlSpot(entry.key.toDouble(), entry.value); }).toList(), color: chartColors[idx], barWidth: 5, isCurved: true, dotData: const FlDotData(show: true), ); }).toList();
API结构优化建议
当前的List<Map<String, List<double>>>结构冗余(每个Map仅含一个键值对),建议优化为以下更直观的格式:
方案1:包含名称与数据的结构化列表
适合需要保留顺序、同时需要产品名称的场景:
var listData = [ { 'productName': 'Product01', 'data': [12.0, 14.5, 15.6, 12.1, 15.2, 17.6, 12.8, 24.0, 35.4, 12.9] }, { 'productName': 'Product02', 'data': [9.0, 12.5, 11.6, 7.1, 10.2, 14.6, 8.8, 18.0, 31.4, 10.9] }, ];
遍历示例:
List<LineChartBarData> sections = listData.asMap().entries.map((data) { final idx = data.key; final productData = data.value; final values = productData['data'] as List<double>; return LineChartBarData( spots: values.asMap().entries.map((entry) => FlSpot(entry.key.toDouble(), entry.value)).toList(), color: chartColors[idx], barWidth: 5, isCurved: true, dotData: const FlDotData(show: true), // 可添加产品名称作为折线图例 belowBarData: BarAreaData(show: false), ); }).toList();
方案2:直接使用Map<String, List>
如果不需要严格顺序,或可通过键排序,直接用单个Map更简洁:
var listData = { 'Product01': [12.0, 14.5, 15.6, 12.1, 15.2, 17.6, 12.8, 24.0, 35.4, 12.9], 'Product02': [9.0, 12.5, 11.6, 7.1, 10.2, 14.6, 8.8, 18.0, 31.4, 10.9], };
遍历示例:
List<LineChartBarData> sections = listData.entries.asMap().entries.map((data) { final idx = data.key; final entry = data.value; final productName = entry.key; final values = entry.value; return LineChartBarData( spots: values.asMap().entries.map((e) => FlSpot(e.key.toDouble(), e.value)).toList(), color: chartColors[idx], barWidth: 5, isCurved: true, dotData: const FlDotData(show: true), ); }).toList();
内容的提问来源于stack exchange,提问作者Ravi
相关产品推荐
相关产品推荐

