Flutter图表绘制插件k_chart_plus的使用
Flutter图表绘制插件k_chart_plus的使用
k_chart_plus
是一个功能强大的Flutter图表绘制插件,支持拖拽、缩放、长按、滑动等交互,并且易于使用。本文将详细介绍如何在Flutter项目中使用该插件。
特性
- 支持拖拽、缩放、长按、滑动。
- 提供K线图和深度图两种图表类型。
- 支持多主题配置(暗黑模式/亮色模式)。
示例效果
Example1 | Example2 |
---|---|
![]() |
![]() |
安装
首先,在 pubspec.yaml
文件中添加 k_chart_plus
依赖:
dependencies:
k_chart_plus: ^1.0.2
如果你不想支持选择多个次要状态,可以使用以下方式添加依赖:
dependencies:
k_chart_plus:
git:
url: https://github.com/TrangLeQuynh/k_chart_plus
ref: single # branch name
使用
数据计算
当你更改数据时,必须调用以下函数:
DataUtil.calculate(datas); // 可选参数:n是BOLL N日收盘价,k是BOLL参数
使用K线图
KChartWidget(
chartStyle, // 必填项,用于样式设置
chartColors,// 必填项,用于样式设置
datas,// 必填项,数据必须是一个有序列表(历史=>现在)
mBaseHeight: 360, // 图表高度(不包含成交量和次级视图)
isLine: isLine,// 决定是否为K线或分时图
mainState: _mainState,// 决定主视图显示的内容
secondaryStateLi: _secondaryStateLi,// 决定次级视图显示的内容
fixedLength: 2,// 显示的小数位数
timeFormat: TimeFormat.YEAR_MONTH_DAY,
onLoadMore: (bool a) {},// 当数据滚动到末尾时调用。a为true表示用户向右拉动到底部,a为false表示用户向左拉动到底部。
maDayList: [5,10,20],// MA显示天数,此参数必须等于DataUtil.calculate中的maDayList
volHidden: false,// 隐藏成交量
showNowPrice: true,// 显示当前价格
isOnDrag: (isDrag){},// true表示正在拖拽。拖拽时不加载数据。
isTrendLine: false, // 设置为true后,可以通过长按并移动手指来使用趋势线。
xFrontPadding: 100 // 前端填充
),
使用深度图
DepthChart(_bids, _asks, chartColors) // 注意:数据必须是一个有序列表
暗黑模式/亮色模式
你可以通过 ChartColor
来设置图表的颜色,确保根据你的主题配置灵活调整UI。
late ThemeData themeData = Theme.of(context);
late ChartColors chartColors = ChartColors(
bgColor: themeData.colorScheme.background,
defaultTextColor: themeData.textTheme.labelMedium?.color ?? Colors.grey,
gridColor: themeData.dividerColor,
hCrossColor: themeData.textTheme.bodyMedium?.color ?? Colors.white,
vCrossColor: themeData.disabledColor.withOpacity(.1),
crossTextColor: themeData.textTheme.bodyMedium?.color ?? Colors.white,
selectBorderColor: themeData.textTheme.bodyMedium?.color ?? Colors.black54,
selectFillColor: themeData.colorScheme.background,
infoWindowTitleColor: themeData.textTheme.labelMedium?.color ?? Colors.grey,
infoWindowNormalColor: themeData.textTheme.bodyMedium?.color ?? Colors.white,
);
应用到K线图中:
KChartWidget(
data,
ChartStyle(),
ChartColors().init(), /// 自定义图表颜色
chartTranslations: ChartTranslations(
date: 'Date',
open: 'Open',
high: 'High',
low: 'Low',
close: 'Close',
changeAmount: 'Change',
change: 'Change%',
amount: 'Amount',
vol: 'Volume',
),
mBaseHeight: 360,
isTrendLine: false,
mainState: mainState,
secondaryStateLi: secondaryStates,
fixedLength: 2,
timeFormat: TimeFormat.YEAR_MONTH_DAY,
);
示例代码
下面是一个完整的示例代码,展示了如何在Flutter项目中使用 k_chart_plus
插件:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
import 'package:k_chart_plus/k_chart_plus.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.deepPurple,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, this.title}) : super(key: key);
final String? title;
[@override](/user/override)
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<KLineEntity>? datas;
bool showLoading = true;
bool _volHidden = false;
MainState _mainState = MainState.MA;
final List<SecondaryState> _secondaryStateLi = [];
List<DepthEntity>? _bids, _asks;
ChartStyle chartStyle = ChartStyle();
ChartColors chartColors = ChartColors();
[@override](/user/override)
void initState() {
super.initState();
getData('1day');
rootBundle.loadString('assets/depth.json').then((result) {
final parseJson = json.decode(result);
final tick = parseJson['tick'] as Map<String, dynamic>;
final List<DepthEntity> bids = (tick['bids'] as List<dynamic>)
.map<DepthEntity>((item) => DepthEntity(item[0] as double, item[1] as double))
.toList();
final List<DepthEntity> asks = (tick['asks'] as List<dynamic>)
.map<DepthEntity>((item) => DepthEntity(item[0] as double, item[1] as double))
.toList();
initDepth(bids, asks);
});
}
void initDepth(List<DepthEntity>? bids, List<DepthEntity>? asks) {
if (bids == null || asks == null || bids.isEmpty || asks.isEmpty) return;
_bids = [];
_asks = [];
double amount = 0.0;
bids.sort((left, right) => left.price.compareTo(right.price));
for (var item in bids.reversed) {
amount += item.vol;
item.vol = amount;
_bids!.insert(0, item);
}
amount = 0.0;
asks.sort((left, right) => left.price.compareTo(right.price));
for (var item in asks) {
amount += item.vol;
item.vol = amount;
_asks!.add(item);
}
setState(() {});
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
shrinkWrap: true,
children: <Widget>[
const SafeArea(bottom: false, child: SizedBox(height: 10)),
Stack(children: <Widget>[
KChartWidget(
datas,
chartStyle,
chartColors,
mBaseHeight: 360,
isTrendLine: false,
mainState: _mainState,
volHidden: _volHidden,
secondaryStateLi: _secondaryStateLi.toSet(),
fixedLength: 2,
timeFormat: TimeFormat.YEAR_MONTH_DAY,
),
if (showLoading)
Container(
width: double.infinity,
height: 450,
alignment: Alignment.center,
child: const CircularProgressIndicator(),
),
]),
_buildTitle(context, 'VOL'),
buildVolButton(),
_buildTitle(context, 'Main State'),
buildMainButtons(),
_buildTitle(context, 'Secondary State'),
buildSecondButtons(),
const SizedBox(height: 30),
if (_bids != null && _asks != null)
Container(
color: Colors.white,
height: 320,
width: double.infinity,
child: DepthChart(
_bids!,
_asks!,
chartColors,
),
)
],
),
);
}
Widget _buildTitle(BuildContext context, String title) {
return Padding(
padding: const EdgeInsets.fromLTRB(16, 20, 12, 15),
child: Text(
title,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
);
}
Widget buildVolButton() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Align(
alignment: Alignment.centerLeft,
child: _buildButton(
context: context,
title: 'VOL',
isActive: !_volHidden,
onPress: () {
_volHidden = !_volHidden;
setState(() {});
}),
),
);
}
Widget buildMainButtons() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Wrap(
alignment: WrapAlignment.start,
spacing: 10,
runSpacing: 10,
children: MainState.values.map((e) {
return _buildButton(
context: context,
title: e.name,
isActive: _mainState == e,
onPress: () => _mainState = e,
);
}).toList(),
),
);
}
Widget buildSecondButtons() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Wrap(
alignment: WrapAlignment.start,
spacing: 10,
runSpacing: 5,
children: SecondaryState.values.map((e) {
bool isActive = _secondaryStateLi.contains(e);
return _buildButton(
context: context,
title: e.name,
isActive: isActive,
onPress: () {
if (isActive) {
_secondaryStateLi.remove(e);
} else {
_secondaryStateLi.add(e);
}
},
);
}).toList(),
),
);
}
Widget _buildButton({
required BuildContext context,
required String title,
required bool isActive,
required Function onPress,
}) {
late Color? bgColor, txtColor;
if (isActive) {
bgColor = Theme.of(context).primaryColor.withOpacity(.15);
txtColor = Theme.of(context).primaryColor;
} else {
bgColor = Colors.transparent;
txtColor =
Theme.of(context).textTheme.bodyMedium?.color?.withOpacity(.75);
}
return InkWell(
onTap: () {
onPress();
setState(() {});
},
child: Container(
decoration: BoxDecoration(
color: bgColor,
borderRadius: BorderRadius.circular(6),
),
constraints: const BoxConstraints(minWidth: 60),
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
child: Text(
title,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: txtColor,
),
textAlign: TextAlign.center,
),
),
);
}
void getData(String period) {
final Future<String> future = getChatDataFromInternet(period);
future.then((String result) {
solveChatData(result);
}).catchError((_) {
showLoading = false;
setState(() {});
debugPrint('### datas error $_');
});
}
Future<String> getChatDataFromInternet(String? period) async {
var url =
'https://api.huobi.br.com/market/history/kline?period=${period ?? '1day'}&size=300&symbol=btcusdt';
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
return response.body;
} else {
debugPrint('Failed getting IP address');
throw Exception('Failed to load data');
}
}
void solveChatData(String result) {
final Map parseJson = json.decode(result) as Map<dynamic, dynamic>;
final list = parseJson['data'] as List<dynamic>;
datas = list
.map((item) => KLineEntity.fromJson(item as Map<String, dynamic>))
.toList()
.reversed
.toList()
.cast<KLineEntity>();
DataUtil.calculate(datas!);
showLoading = false;
setState(() {});
}
}
更多关于Flutter图表绘制插件k_chart_plus的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter图表绘制插件k_chart_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用k_chart_plus
插件来绘制图表的示例代码。k_chart_plus
是一个强大的Flutter图表绘制插件,支持多种类型的图表,如折线图、柱状图、饼图等。
首先,你需要在你的pubspec.yaml
文件中添加k_chart_plus
依赖:
dependencies:
flutter:
sdk: flutter
k_chart_plus: ^最新版本号 # 请替换为实际的最新版本号
然后运行flutter pub get
来安装依赖。
接下来是一个简单的示例,展示如何使用k_chart_plus
绘制一个基本的折线图:
import 'package:flutter/material.dart';
import 'package:k_chart_plus/k_chart_plus.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('k_chart_plus Demo'),
),
body: Center(
child: LineChartDemo(),
),
),
);
}
}
class LineChartDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 数据准备
final List<double> xData = [1, 2, 3, 4, 5];
final List<double> yData = [2, 3, 5, 7, 11];
// 配置图表
final LineChartData lineChartData = LineChartData(
linesData: [
LineChartLineData(
label: 'Line 1',
data: List.generate(xData.length, (index) {
return LineChartDataPoint(xData[index], yData[index]);
}),
color: Colors.blue,
strokeWidth: 2,
),
],
title: 'Line Chart Demo',
description: 'This is a simple line chart example.',
xAxisTitle: 'X Axis',
yAxisTitle: 'Y Axis',
grid: GridData(show: true),
animationDuration: Duration(milliseconds: 1000),
);
// 构建图表
return LineChart(lineChartData);
}
}
在这个示例中:
- 数据准备:我们定义了两个列表
xData
和yData
,分别存储X轴和Y轴的数据。 - 配置图表:使用
LineChartData
类来配置图表的各种属性,如线条数据、标题、描述、轴标题、网格线以及动画持续时间。 - 构建图表:使用
LineChart
组件来渲染配置好的图表数据。
运行这个示例,你将会看到一个简单的折线图。你可以根据需要进一步自定义图表的样式和数据。k_chart_plus
插件提供了丰富的配置选项,可以满足大多数图表绘制需求。
希望这个示例对你有所帮助!如果有更多问题,欢迎继续提问。