如何在Flutter中绘制带左侧工具栏的蜡烛图(Candle Chart)
Flutter实现带左侧工具栏蜡烛图的完整方案
效果参考
实现方式选择
有两种主流实现方案,可根据需求复杂度选择:
- 需求偏通用,不需要极高定制化:直接用成熟的第三方图表库开发,效率最高
- 有大量自定义交互、特殊样式需求:使用
CustomPainter自行绘制蜡烛图,灵活度最高
方案1:使用fl_chart第三方库实现(推荐)
fl_chart是Flutter生态中最成熟的开源图表库,原生支持蜡烛图组件,同时支持缩放、平移、坐标轴自定义等常见需求,左侧工具栏可通过布局单独实现,和图表组件解耦。
步骤1:添加依赖
在pubspec.yaml中添加依赖,可自行替换为当前最新稳定版本:
dependencies: flutter: sdk: flutter fl_chart: ^0.65.0
步骤2:定义蜡烛数据模型
class CandleEntry { final double open; // 开盘价 final double high; // 最高价 final double low; // 最低价 final double close; // 收盘价 final DateTime time; // 时间 }
步骤3:实现基础布局与图表渲染
核心用Row布局拆分左侧工具栏和右侧蜡烛图区域,交互可通过状态管理实现二者的联动:
import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; class CandleChartPage extends StatefulWidget { const CandleChartPage({super.key}); @override State<CandleChartPage> createState() => _CandleChartPageState(); } class _CandleChartPageState extends State<CandleChartPage> { // 示例蜡烛数据,实际使用时替换为接口返回的真实数据 List<CandleEntry> candleList = [ CandleEntry(open: 100, high: 120, low: 90, close: 110, time: DateTime.now().subtract(const Duration(days: 4))), CandleEntry(open: 110, high: 130, low: 105, close: 125, time: DateTime.now().subtract(const Duration(days: 3))), CandleEntry(open: 125, high: 140, low: 115, close: 120, time: DateTime.now().subtract(const Duration(days: 2))), CandleEntry(open: 120, high: 125, low: 100, close: 105, time: DateTime.now().subtract(const Duration(days: 1))), CandleEntry(open: 105, high: 115, low: 95, close: 110, time: DateTime.now()), ]; @override Widget build(BuildContext context) { return Scaffold( body: Row( children: [ // 左侧工具栏,可自行添加需要的功能按钮 Container( width: 60, color: Colors.grey[200], child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ IconButton(icon: const Icon(Icons.zoom_in), onPressed: () { // 实现缩放逻辑 }), IconButton(icon: const Icon(Icons.pan_tool), onPressed: () { // 实现平移逻辑 }), IconButton(icon: const Icon(Icons.show_chart), onPressed: () { // 切换指标逻辑 }), IconButton(icon: const Icon(Icons.settings), onPressed: () { // 图表设置逻辑 }), ], ), ), // 右侧蜡烛图区域 Expanded( child: CandleChart( CandleChartData( candleBodies: candleList.map((data) { final isGain = data.close >= data.open; return CandleChartCandleData( x: candleList.indexOf(data).toDouble(), high: data.high, low: data.low, open: data.open, close: data.close, bullColor: Colors.green, bearColor: Colors.red, ); }).toList(), borderData: FlBorderData(show: true), gridData: FlGridData(show: true), titlesData: FlTitlesData( leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, reservedSize: 40)), bottomTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, reservedSize: 30)), topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)), rightTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)), ), ), ), ), ], ), ); } }
方案2:自定义绘制实现
如果需要高度定制的交互、特殊样式,可通过CustomPainter自行绘制蜡烛图,核心逻辑是计算每个蜡烛的位置、尺寸,分别绘制影线和实体,再叠加手势检测器实现缩放、平移操作,左侧工具栏的实现逻辑和方案1完全一致。
注意事项
- 涨跌颜色可根据产品需求调整,国内金融产品通常是红涨绿跌,海外产品通常是绿涨红跌
- 数据量较大时建议做分页懒加载、可视区域渲染优化,避免滑动卡顿
- 工具栏和图表的联动可通过
Provider、Bloc等状态管理方案实现,解耦二者的逻辑
内容的提问来源于stack exchange,提问作者Navid Shokoufeh
相关产品推荐
相关产品推荐

