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

Flutter fl_chart绘制日期折线图 日期过多、配置minX/maxX卡顿问题

问题根因

两个核心逻辑错误直接触发你遇到的所有异常:

  1. 折线坐标与轴范围完全错配:生成折线点位时,你把X值替换成了列表索引(0、1、2……这类个位数),但计算minX/maxX时用的是日期转成的13位毫秒时间戳,两者量级差超过10^10。fl_chart会尝试在跨度达数十亿的数值区间内按默认步长渲染刻度、网格线,计算量直接爆掉,必然卡死。
  2. 刻度配置逻辑错误:X轴刻度间隔设为首尾日期的总时间差,同时没有做无效刻度过滤,组件会遍历区间内所有毫秒值尝试生成标签,直接出现大量冗余日期。
  3. 附加卡顿点:网格线横纵间隔都设为1,配合错误的X轴范围,会尝试绘制数百万条透明网格线,进一步拖慢性能。
修复方案

按以下步骤替换对应代码块即可:

  1. 修正折线点位,不要用索引替换原始时间戳X值
  2. 重新配置网格线、X轴刻度的间隔值,匹配日期维度的实际步长
  3. 增加无效刻度过滤逻辑,只渲染实际存在数据的日期标签
  4. 替换字符串切割的日期格式化逻辑,避免时区偏移导致的日期显示错误

核心代码修改

1. 修正折线点位生成

找到lineBarsData配置块,把原来错误的spots生成逻辑替换为直接使用原始点位:

lineBarsData: [
  LineChartBarData(
    // 直接使用预处理好的flSpots,禁止用列表索引替换X值
    spots: flSpots,
    isCurved: false,
    color: primaryColorGreen,
    barWidth: 2,
    isStrokeCapRound: true,
    dotData: FlDotData(show: true),
    belowBarData: BarAreaData(
      show: true,
      gradient: LinearGradient(
        colors: gradientColors.map((color) => color.withOpacity(0.3)).toList(),
        begin: Alignment.topCenter,
        end: Alignment.bottomCenter,
      ),
    ),
  ),
]

2. 修正网格线间隔

找到gridData配置块,替换间隔参数为合理值:

gridData: FlGridData(
  show: true,
  drawVerticalLine: true,
  // Y轴间隔匹配你的销售额步长,示例为每1000单位画一条横线
  horizontalInterval: 1000,
  // X轴间隔匹配日期步长,示例为每1天对应毫秒数,可按需改成7天/30天
  verticalInterval: 24 * 60 * 60 * 1000,
  getDrawingHorizontalLine: (value) => FlLine(color: borderColor, strokeWidth: 1),
  getDrawingVerticalLine: (value) => FlLine(color: Colors.transparent, strokeWidth: 1),
)

3. 增加X轴刻度过滤

在mainData方法开头新增有效X值集合,用来过滤无效刻度:

LineChartData mainData(List<FlSpot>? flSpots) {
  final List<double> xList = [];
  final List<double> yList = [];
  // 存储所有真实存在数据的X轴毫秒值
  final Set<double> validXSet = {};
  flSpots?.forEach((e) {
    xList.add(e.x);
    yList.add(e.y);
    validXSet.add(e.x);
  });

  final minX = xList.reduce(min);
  final maxX = xList.reduce(max);
  final minY = yList.reduce(min);
  final maxY = ((yList.reduce(max)) + 1000).toInt().toDouble();
  // ...... 其他原有配置保留,修改bottomTitles部分

替换bottomTitles配置:

bottomTitles: AxisTitles(
  sideTitles: SideTitles(
    showTitles: true,
    reservedSize: 30,
    interval: 24 * 60 * 60 * 1000,
    // 过滤无效刻度,只渲染真实有数据的日期
    getTitlesWidget: (value, meta) {
      if (!validXSet.contains(value)) return const SizedBox.shrink();
      return bottomTitleWidgets(value, meta);
    },
  )
)

4. 优化日期格式化

提前初始化日期格式化器(建议放在类成员位置,不要每次build重建),替换原来的字符串切割逻辑,避免时区问题:

// 类成员位置初始化,需要引入intl包
final _dateFormatter = DateFormat('yyyy-MM-dd');

Widget bottomTitleWidgets(double value, TitleMeta meta) {
  const style = TextStyle(
    height: 1,
    color: placeholderColor,
    fontWeight: weight500,
    fontSize: fontsize12,
  );
  final date = DateTime.fromMillisecondsSinceEpoch(value.toInt());
  return SideTitleWidget(
    space: 12,
    axisSide: meta.axisSide,
    child: Text(_dateFormatter.format(date), style: style),
  );
}
可选优化
  • 数据量大于20条时,不需要给每个点都显示X轴标签,可固定只渲染首、中、尾3-5个标签,减少渲染压力
  • 计算minX/maxX时可各增减1天的毫秒值作为padding,避免首尾数据点贴在图表边缘
  • FlSpot列表、有效X值集合建议在拿到业务数据时就提前转换完成,不要放在build方法里遍历计算

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 11:57:21