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

Flutter fl_chart:为X轴添加倾斜的格式化日期标签

Flutter fl_chart柱状图X轴倾斜日期标签布局问题

需求:用fl_chart包实现柱状图,X轴需以dd/MM/yy格式显示倾斜的日期标签。

问题:

  • 当前UI效果不符合预期
  • 尝试给文本标题添加顶部内边距向下移动10单位时,文本直接消失
  • ClaimsChart组件嵌套在SingleChildScrollView中

当前实现代码:

import 'dart:math';

import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:vendors/gen/colors.gen.dart';
import 'package:vendors/src/shared/widgets/dividers/custom_divider.dart';
import 'package:vendors/src/shared/widgets/input/input_date_field.dart';

class ClaimsChart extends StatefulWidget {
  const ClaimsChart({super.key});

  @override
  State<ClaimsChart> createState() => _ClaimsChartState();
}

class _ClaimsChartState extends State<ClaimsChart> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: [
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 12.0),
            child: Column(
              children: [
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    // 原代码此处可能缺失日期选择类组件
                  ],
                ),
                const CustomDivider(),
                AspectRatio(
                  aspectRatio: 1.75,
                  child: Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 4.0),
                    child: BarChart(
                      BarChartData(
                        barGroups: _chartGroups(),
                        borderData: FlBorderData(
                            border: const Border(
                                bottom: BorderSide(color: Colors.black26),
                                left: BorderSide(color: Colors.black26))),
                        gridData: const FlGridData(show: false),
                        titlesData: FlTitlesData(
                          bottomTitles: AxisTitles(sideTitles: _bottomTitles),
                          leftTitles: AxisTitles(
                              sideTitles: SideTitles(
                                  showTitles: true,
                                  interval: 5,
                                  reservedSize: 20,
                                  getTitlesWidget: (value, meta) => Text(
                                        value.toInt().toString(),
                                        style: TextStyle(
                                            color: Colors.black.withOpacity(0.6),
                                            fontSize: 12),
                                      ))),
                          topTitles: const AxisTitles(
                              sideTitles: SideTitles(showTitles: false)),
                          rightTitles: const AxisTitles(
                              sideTitles: SideTitles(showTitles: false)),
                        ),
                      ),
                    ),
                  ),
                )
              ],
            ),
          )
        ],
      ),
    );
  }

  List<BarChartGroupData> _chartGroups() {
    return List.generate(
            10,
            (index) =>
                ChartData(date: DateTime.now().subtract(Duration(days: index)), value: Random().nextInt(20)))
        .map((point) =>
            BarChartGroupData(x: point.date.microsecondsSinceEpoch, barRods: [
              BarChartRodData(
                  toY: point.value.toDouble(),
                  color: ColorName.barChart,
                  width: 12,
                  borderRadius: BorderRadius.circular(0)),
            ]))
        .toList();
  }

  SideTitles get _bottomTitles => SideTitles(
        showTitles: true,
        reservedSize: 40, // 预留足够空间容纳旋转后的文本
        getTitlesWidget: (value, meta) {
          String formattedDate = DateFormat("dd/MM/yy")
              .format(DateTime.fromMicrosecondsSinceEpoch(value.toInt()));
          return SideTitleWidget(
              axisSide: meta.axisSide,
              space: 8, // 控制文本与X轴的间距
              child: Transform.rotate(
                angle: -45 * (pi / 180),
                alignment: Alignment.centerRight,
                child: Text(
                  formattedDate,
                  textAlign: TextAlign.right,
                  style: TextStyle(
                    color: Colors.black.withOpacity(0.6),
                    fontSize: 12,
                  ),
                ),
              ));
        },
      );
}

class ChartData {
  final DateTime date;
  final int value;

  ChartData({required this.date, this.value = 9});
}

当前UI:
当前UI

预期UI:
预期UI

关键修复点:

  1. 预留底部标题空间:给SideTitles设置reservedSize: 40,确保旋转后的文本不会被裁剪
  2. 修正日期格式化:把dd/mm/yy改成dd/MM/yy(mm代表分钟,MM才是月份)
  3. 生成连续日期:_chartGroups里生成递减的日期,避免X轴标签重复
  4. 调整旋转对齐与间距:修改Transform.rotate的alignment为Alignment.centerRight,通过SideTitleWidget的space属性控制文本与X轴的距离,替代容易导致裁剪的内边距

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 12:35:10