一.折线图入门
效果图

代码逻辑
1.坐标范围
2.网格线
3.坐标文字
4.边框
5.折线数据
6.交互行为(点击折线区域)
代码实例
Dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart'; //导入包
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<StatefulWidget> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
//构建UI
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("折线图入门示例")),
body: Padding(
padding: const EdgeInsets.all(16.0),
child:
LineChart( //f1_chart提供的主控件,用于显示折线图
mainData(),
),
),
);
}
// 折线图配置
LineChartData mainData() {
return LineChartData(
//1.坐标范围
minX: 0,
maxX: 6,
minY: 0,
maxY: 6,
//2.网格线
gridData: FlGridData(
//默认情况下内部线是虚线,外部线是实线
show: true,//启动网格
horizontalInterval: 1, //每隔一个单元绘制一条水平线
verticalInterval: 1, //每隔一个单元绘制一条垂直线
// getDrawingHorizontalLine: (value) { //内部横实线
// return FlLine(
// color: Colors.grey,
// strokeWidth: 1,
// dashArray: null, // 设为0或null代表实线
// );
// },
//
// getDrawingVerticalLine: (value) { //内部竖实线
// return FlLine(
// color: Colors.grey.withOpacity(0.5),
// strokeWidth: 1,
// dashArray: null, // ← 实线
// );
// },
),
//3.坐标文字
titlesData: FlTitlesData(
bottomTitles: //横轴
AxisTitles(
sideTitles: SideTitles(
showTitles: true, //打开X轴标签显示
interval: 1,//每隔1单位画一个刻度并显示数字
getTitlesWidget: (value, meta) { //显示每个X值对应显示什么文字(会覆盖默认的显示数字)
const style = TextStyle(fontSize: 12);
switch (value.toInt()) {
case 0: return const Text("一", style: style);
case 1: return const Text("二", style: style);
case 2: return const Text("三", style: style);
case 3: return const Text("四", style: style);
case 4: return const Text("五", style: style);
case 5: return const Text("六", style: style);
case 6: return const Text("日", style: style);
}
return const Text("");
},
),
),
leftTitles: //纵轴
AxisTitles(
sideTitles: SideTitles(
showTitles: true, //打开Y轴标签显示
interval: 1,//每隔1单位画一个刻度并显示数字(默认显示Y轴数字)
),
),
rightTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),//右侧轴
topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)), //顶部轴
),
//4.边框
borderData: FlBorderData(
show: true, //显示边框
border: Border.all(color: Colors.red),
),
//5.折线数据
lineBarsData: [
LineChartBarData(
isCurved: true, // 是否平滑曲线
color: Colors.blue, //折线颜色
barWidth: 3,
dotData: FlDotData(show: true), // 显示折线点
belowBarData: BarAreaData( //曲线下方区域
show: true,
color: Colors.blue.withOpacity(0.2), // 曲线下方阴影颜色
),
spots: const [ //折线的点的数据
FlSpot(0, 1),
FlSpot(1, 3),
FlSpot(2, 5),
FlSpot(3, 4.5),
FlSpot(4, 3.5),
FlSpot(5, 5),
FlSpot(6, 4),
],
),
],
//6.用来控制折线图的触摸和交互行为
lineTouchData: LineTouchData(
touchTooltipData: LineTouchTooltipData(
tooltipBgColor: Colors.blueAccent.withOpacity(0.8),
),
handleBuiltInTouches: true, // 启用点击浮窗
),
);
}
}
二.交互式折线图
效果图

代码逻辑
1.定义输入框控制器和焦点控制器
2.初始化存储数据点的列表
3.定义取消焦点的方法
4.定义添加数据点的方法
5.定义删除数据点的方法
6.定义清除所有数据点的方法
7.销毁的相关操作
8.具体UI(输入行,添加按钮,清空按钮,折线图区域,当前坐标点列表)
9.折线图的具体配置
代码实例
Dart
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<StatefulWidget> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final TextEditingController _xController = TextEditingController(); //输入框控制器
final TextEditingController _yController = TextEditingController(); //输入框控制器
final FocusNode _xFocusNode = FocusNode();
final FocusNode _yFocusNode = FocusNode();
List<FlSpot> userSpots = [ //存储用户输入的数据点
const FlSpot(0, 1), //初始的数据点
const FlSpot(1, 2),
const FlSpot(2, 3),
];
//=================================取消焦点方法==================================
void _unfocusAll() {
_xFocusNode.unfocus(); // 取消X输入框焦点
_yFocusNode.unfocus(); // 取消Y输入框焦点
}
//============================添加数据点的方法=================================
void _addPoint() {
double? x = double.tryParse(_xController.text);
double? y = double.tryParse(_yController.text);
if (x != null && y != null && x <= 10 && y <= 10 ) {
setState(() {
userSpots.add(FlSpot(x, y));//添加新点
userSpots.sort((a, b) => a.x.compareTo(b.x));//按X坐标排序
});
//恢复数据框
_xController.clear();
_yController.clear();
_unfocusAll();//取消焦点
} else {
//输入无效时显示提示
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("请输入小于或等于10的有效数字")),
);
_unfocusAll(); // 错误时也取消焦点
}
}
//============================删除数据点的方法=================================
void _removePoint(int index) {
setState(() {
userSpots.removeAt(index); //删除指定索引的点
});
}
//=============================清除所有数据点的方法=============================
void _clearAll() {
setState(() {
userSpots.clear();//清空所有点
_unfocusAll(); // 清空时也取消焦点
});
}
@override
void dispose() {
_xController.dispose();
_yController.dispose();
_xFocusNode.dispose();
_yFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("交互式折线图")),
body: Padding(
padding: const EdgeInsets.all(10),
child: Column(
children: [
// 1.输入行
Row(
children: [
//X坐标输入框
Expanded(
child: TextField(
controller: _xController,
focusNode: _xFocusNode, // 绑定FocusNode
keyboardType: TextInputType.number, //数字键盘
decoration: const InputDecoration(
labelText: "X 坐标",
border: OutlineInputBorder(),
),
),
),
const SizedBox(width: 10),
//Y坐标输入框
Expanded(
child: TextField(
controller: _yController,
focusNode: _yFocusNode, // 绑定FocusNode
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: "Y 坐标",
border: OutlineInputBorder(),
),
),
),
const SizedBox(width: 10),
//添加按钮
ElevatedButton(
onPressed: _addPoint, //添加的点击事件
child: const Text("添加"),
),
],
),
const SizedBox(height: 15),
//2.清空按钮
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton.icon(
onPressed: userSpots.isEmpty ? null : _clearAll, //点击事件
icon: const Icon(Icons.delete_forever, color: Colors.red),
label: const Text(
"清空所有",
style: TextStyle(color: Colors.red),
),
),
],
),
const SizedBox(height: 10),
// 3.折线图区域
Expanded(
flex: 2,
child: LineChart(mainData()),
),
const SizedBox(height: 20),
//4.当前坐标点列表
Expanded(
flex: 1,
child: userSpots.isEmpty
? const Center(child: Text("暂无数据点"))
: ListView.builder(
itemCount: userSpots.length,
itemBuilder: (context, index) {
final spot = userSpots[index];
return Card(
child: ListTile(
leading: const Icon(Icons.circle, color: Colors.blue),
title: Text("X: ${spot.x}, Y: ${spot.y}"),
trailing: IconButton(
icon: const Icon(Icons.delete, color: Colors.red),
onPressed: () => _removePoint(index),
),
),
);
},
),
),
],
),
),
);
}
//===================================折线图配置==================================
LineChartData mainData() {
return LineChartData(
//1,范围
minX: 0, maxX: 10, //x轴范围
minY: 0, maxY: 10, //Y轴范围
//2.网格线
gridData: FlGridData(show: true),
//3.坐标轴标签
titlesData: FlTitlesData(
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
interval: 1,
reservedSize: 30, //为标签保留空间
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
interval: 1, //标签间隔
reservedSize: 30, //为标签保留空间
),
),
rightTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
),
//4.边框
borderData: FlBorderData(
show: true,
border: Border.all(color: Colors.black26),
),
//5.折线数据
lineBarsData: [
LineChartBarData(
isCurved: true, //曲线连接
color: Colors.blue, //线条颜色
barWidth: 3, //线条宽度
dotData: FlDotData(show: true),//显示数据点
belowBarData: BarAreaData(show: true, color: Colors.blue.withOpacity(0.2)), //区域填充
spots: userSpots.isNotEmpty
? userSpots
: [const FlSpot(0, 0)], // 防止空图报错
),
],
//6.交互行为
lineTouchData: LineTouchData(
touchTooltipData: LineTouchTooltipData(
tooltipBgColor: Colors.blueAccent.withOpacity(0.8),
),
handleBuiltInTouches: true,
),
);
}
}