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

如何将Flutter图表代码重构为搭载Scaffold的StatefulWidget?

Flutter fl_chart 嵌入StatefulWidget+Scaffold实现方案

你现有的LineTitles静态配置类不需要大幅修改,核心是将图表嵌入StatefulWidget的构建逻辑,用Scaffold作为页面根容器即可,以下是可直接运行的完整实现。

1. 现有代码适配说明

你写的LineTitles是纯逻辑工具类,不依赖组件生命周期,仅做了两处小优化:

  • 方法名调整为Dart规范的小驼峰格式getTitleData(原大写开头的命名也可正常运行,不做强制要求)
  • 新增了顶部、右侧标题的隐藏配置,避免页面显示冗余刻度

2. 完整可运行代码

import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';

// 原有标题配置类,可直接复用
class LineTitles {
  static FlTitlesData getTitleData() => FlTitlesData(
        show: true,
        // 隐藏右侧和顶部冗余标题
        rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
        topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
        bottomTitles: AxisTitles(
          sideTitles: SideTitles(
              showTitles: true,
              reservedSize: 35,
              getTitlesWidget: (value, meta) {
                switch (value.toInt()) {
                  case 2:
                    return const Text(
                      'MAR',
                      style: TextStyle(
                        color: Color(0xff68737d),
                        fontWeight: FontWeight.bold,
                        fontSize: 16,
                      ),
                    );
                  case 5:
                    return const Text(
                      'JUN',
                      style: TextStyle(
                        color: Color(0xff68737d),
                        fontWeight: FontWeight.bold,
                        fontSize: 16,
                      ),
                    );
                  case 8:
                    return const Text('SEP',
                        style: TextStyle(
                          color: Color(0xff68737d),
                          fontWeight: FontWeight.bold,
                          fontSize: 16,
                        ));
                }
                return const Text(" ");
              }),
        ),
        leftTitles: AxisTitles(
            sideTitles: SideTitles(
                showTitles: true,
                reservedSize: 35,
                getTitlesWidget: (value, meta) {
                  switch (value.toInt()) {
                    case 1:
                      return const Text(
                        '10k',
                        style: TextStyle(
                          color: Color(0xff68737d),
                          fontWeight: FontWeight.bold,
                          fontSize: 15,
                        ),
                      );
                    case 3:
                      return const Text(
                        '30k',
                        style: TextStyle(
                          color: Color(0xff68737d),
                          fontWeight: FontWeight.bold,
                          fontSize: 15,
                        ),
                      );
                    case 5:
                      return const Text('50k',
                          style: TextStyle(
                            color: Color(0xff68737d),
                            fontWeight: FontWeight.bold,
                            fontSize: 15,
                          ));
                  }
                  return const Text(" ");
                })),
      );
}

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.light(useMaterial3: true),
      home: const ChartPage(),
    );
  }
}

// 动态图表页面,使用StatefulWidget实现
class ChartPage extends StatefulWidget {
  const ChartPage({super.key});

  @override
  State<ChartPage> createState() => _ChartPageState();
}

class _ChartPageState extends State<ChartPage> {
  // 折线数据存在状态类中,后续可动态修改
  List<FlSpot> chartSpots = const [
    FlSpot(0, 1),
    FlSpot(2, 2),
    FlSpot(5, 3),
    FlSpot(8, 4),
    FlSpot(10, 5),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('业务数据折线图'),
        centerTitle: true,
      ),
      body: Padding(
        padding: const EdgeInsets.all(24.0),
        child: AspectRatio(
          aspectRatio: 1.5,
          child: LineChart(
            LineChartData(
              titlesData: LineTitles.getTitleData(),
              minX: 0,
              maxX: 10,
              minY: 0,
              maxY: 6,
              gridData: const FlGridData(show: true),
              borderData: FlBorderData(show: true),
              lineBarsData: [
                LineChartBarData(
                  spots: chartSpots,
                  isCurved: true,
                  color: Colors.blue,
                  barWidth: 3,
                  dotData: const FlDotData(show: true),
                )
              ],
            ),
          ),
        ),
      ),
      // 示例浮动按钮,演示动态更新数据逻辑
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            // 修改状态即可触发图表重绘
            chartSpots = const [
              FlSpot(0, 2),
              FlSpot(2, 3),
              FlSpot(5, 4),
              FlSpot(8, 5),
              FlSpot(10, 3),
            ];
          });
        },
        child: const Icon(Icons.refresh),
      ),
    );
  }
}

3. 动态更新图表的使用方式

  • 所有需要动态修改的图表配置(比如折线点数据、选中状态、时间维度)都定义在State类的成员变量中,和示例里的chartSpots逻辑一致
  • 需要更新图表时,在交互逻辑(按钮点击、接口返回、选择器切换)里调用setState()修改对应变量,图表会自动重绘生效
  • 静态标题配置每次build时都会自动加载,不会因为状态更新出现显示异常
  • 可以根据业务需求在Scaffold中扩展其他模块:比如在appBar下加筛选栏、在图表周围加数据统计卡片、在底部加操作按钮,和普通Widget布局逻辑完全一致

注意事项

  • 提前在pubspec.yaml中添加fl_chart依赖,当前代码适配0.6.x及以上版本,和你现有代码的API完全匹配
  • 如果需要调整图表尺寸,在外层嵌套Container或AspectRatio组件约束宽高即可,避免布局溢出

内容的提问来源于stack exchange,提问作者pomoworko.com

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 08:12:48