Flutter 三方库 fl_chart 适配 OpenHarmony ———实现 自定义 柱状图
通过SideTitles类,我们可以自定义坐标轴的标题、样式和显示方式。case 0: return const Text('周一');case 1: return const Text('周二');case 2: return const Text('周三');case 3: return const Text('周四');case 4: return const Text('周五');case
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net
引言
在移动应用开发中,数据可视化已经成为不可或缺的功能。无论是金融分析、健康追踪还是业务报表,图表都能直观地展示数据趋势和关系。Flutter 作为跨平台开发框架,为开发者提供了一套统一的代码库,可在 iOS、Android、Web 等多个平台运行。然而,随着 OpenHarmony 生态的快速发展,如何将现有的 Flutter 图表库适配到 OpenHarmony 平台成为了一个新的挑战。
fl_chart 是 Flutter 生态中一款功能强大的图表库,以其高度自定义能力和美观的视觉效果著称。它支持多种图表类型,包括线图、柱状图、饼图等,并且提供了丰富的配置选项,让开发者可以根据需求创建各种复杂的图表。
混合工程结构深度解析
项目目录架构
当Flutter项目集成鸿蒙支持后,典型的项目结构会发生显著变化。以下是经过ohos_flutter插件初始化后的项目结构:
my_flutter_harmony_app/
├── lib/ # Flutter业务代码(基本不变)
│ ├── main.dart # 应用入口
│ ├── home_page.dart # 首页
│ └── utils/
│ └── platform_utils.dart # 平台工具类
├── pubspec.yaml # Flutter依赖配置
├── ohos/ # 鸿蒙原生层(核心适配区)
│ ├── entry/ # 主模块
│ │ └── src/main/
│ │ ├── ets/ # ArkTS代码
│ │ │ ├── MainAbility/
│ │ │ │ ├── MainAbility.ts # 主Ability
│ │ │ │ └── MainAbilityContext.ts
│ │ │ └── pages/
│ │ │ ├── Index.ets # 主页面
│ │ │ └── Splash.ets # 启动页
│ │ ├── resources/ # 鸿蒙资源文件
│ │ │ ├── base/
│ │ │ │ ├── element/ # 字符串等
│ │ │ │ ├── media/ # 图片资源
│ │ │ │ └── profile/ # 配置文件
│ │ │ └── en_US/ # 英文资源
│ │ └── config.json # 应用核心配置
│ ├── ohos_test/ # 测试模块
│ ├── build-profile.json5 # 构建配置
│ └── oh-package.json5 # 鸿蒙依赖管理
└── README.md
展示效果图片
flutter 实时预览 效果展示

运行到鸿蒙虚拟设备中效果展示
依赖配置
具体配置方法
在 Flutter 项目中集成 fl_chart 库非常直接。首先,我们需要在 pubspec.yaml 文件中添加依赖:
dependencies:
flutter:
sdk: flutter
# 图表库
fl_chart: ^0.68.0
添加依赖后,执行 flutter pub get 命令来获取包。对于 OpenHarmony 项目,我们还需要确保 ohos 目录结构正确,并且构建配置文件(如 build-profile.json5 和 hvigorfile.ts)设置合理,以支持 Flutter 应用的构建和运行。
配置中遇到的问题和解决方案
在配置过程中,我遇到了一些常见问题:
-
依赖版本冲突:当项目中存在其他依赖与 fl_chart 版本不兼容时,可能会导致构建失败。解决方案是使用
flutter pub outdated检查依赖版本,并根据需要更新或固定版本。 -
OpenHarmony 构建配置:初次适配时,可能会遇到构建配置错误。解决方案是参考 OpenHarmony 官方文档,确保
module.json5和其他配置文件正确设置。 -
网络依赖下载:在某些环境下,可能会遇到依赖下载缓慢或失败的问题。解决方案是配置合适的镜像源,或使用离线依赖包。
基础柱状图实现
实现方法
实现一个基础的柱状图需要以下步骤:
-
导入依赖:在需要使用图表的文件中导入 fl_chart 库。
-
创建数据模型:准备图表所需的数据点,使用
BarChartGroupData和BarChartRodData表示每个柱子的数据。 -
配置图表参数:创建
BarChartData对象,设置图表的各种参数,如数据系列、坐标范围、网格等。 -
构建图表组件:使用
BarChart组件,将配置好的BarChartData对象作为参数传入。
以下是一个基础柱状图的实现示例:
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
class BarChartComponent extends StatefulWidget {
const BarChartComponent({Key? key}) : super(key: key);
_BarChartComponentState createState() => _BarChartComponentState();
}
class _BarChartComponentState extends State<BarChartComponent> {
int touchedIndex = -1;
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16.0),
child: BarChart(
BarChartData(
barTouchData: BarTouchData(
touchCallback: (FlTouchEvent event, barTouchResponse) {
setState(() {
if (!event.isInterestedForInteractions ||
barTouchResponse == null ||
barTouchResponse.spot == null) {
touchedIndex = -1;
return;
}
touchedIndex = barTouchResponse.spot!.touchedBarGroupIndex;
});
},
),
titlesData: FlTitlesData(
show: true,
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: (value, meta) {
switch (value.toInt()) {
case 0: return const Text('周一');
case 1: return const Text('周二');
case 2: return const Text('周三');
case 3: return const Text('周四');
case 4: return const Text('周五');
case 5: return const Text('周六');
case 6: return const Text('周日');
default: return const Text('');
}
},
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: (value, meta) {
return Text('$value');
},
),
),
),
barGroups: List.generate(7, (index) {
final isTouched = index == touchedIndex;
final color = isTouched ? Colors.blue : Colors.blue.withOpacity(0.6);
final width = isTouched ? 25.0 : 20.0;
switch (index) {
case 0: return BarChartGroupData(x: 0, barRods: [BarChartRodData(toY: 10, color: color, width: width)]);
case 1: return BarChartGroupData(x: 1, barRods: [BarChartRodData(toY: 15, color: color, width: width)]);
case 2: return BarChartGroupData(x: 2, barRods: [BarChartRodData(toY: 12, color: color, width: width)]);
case 3: return BarChartGroupData(x: 3, barRods: [BarChartRodData(toY: 20, color: color, width: width)]);
case 4: return BarChartGroupData(x: 4, barRods: [BarChartRodData(toY: 18, color: color, width: width)]);
case 5: return BarChartGroupData(x: 5, barRods: [BarChartRodData(toY: 25, color: color, width: width)]);
case 6: return BarChartGroupData(x: 6, barRods: [BarChartRodData(toY: 16, color: color, width: width)]);
default: return BarChartGroupData(x: index, barRods: [BarChartRodData(toY: 0, color: color, width: width)]);
}
}),
),
),
);
}
}
实现中遇到的问题和解决方案
在实现过程中,我遇到了以下问题:
-
y 轴标签显示问题:初次实现时,y 轴标签显示的是 “$value” 字符串,而不是实际的数值。解决方案是将
'\$value'改为'$value',确保正确显示数值。 -
常量表达式错误:在使用
const Column时,由于Colors.grey[700]不是常量表达式,导致编译错误。解决方案是从Column中移除const关键字。 -
参数不存在错误:使用
tooltipBgColor参数时,编译器提示该参数不存在。解决方案是查看 fl_chart 库的文档,使用正确的参数名称或移除不存在的参数。
高度自定义配置详解
坐标轴定制
通过 SideTitles 类,我们可以自定义坐标轴的标题、样式和显示方式。例如,我们可以为横坐标设置星期几标签,为纵坐标设置数值标签:
titlesData: FlTitlesData(
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: (value, meta) {
switch (value.toInt()) {
case 0: return const Text('周一');
case 1: return const Text('周二');
case 2: return const Text('周三');
case 3: return const Text('周四');
case 4: return const Text('周五');
case 5: return const Text('周六');
case 6: return const Text('周日');
default: return const Text('');
}
},
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: (value, meta) {
return Text('$value');
},
),
),
),
触摸交互与 Tooltip
通过 BarTouchData,我们可以启用触摸交互和 Tooltip,提升用户体验:
barTouchData: BarTouchData(
touchTooltipData: BarTouchTooltipData(
getTooltipItem: (group, groupIndex, rod, rodIndex) {
String weekDay;
switch (group.x.toInt()) {
case 0: weekDay = '周一'; break;
case 1: weekDay = '周二'; break;
case 2: weekDay = '周三'; break;
case 3: weekDay = '周四'; break;
case 4: weekDay = '周五'; break;
case 5: weekDay = '周六'; break;
case 6: weekDay = '周日'; break;
default: weekDay = '';
}
return BarTooltipItem(
'$weekDay\n',
const TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 14,
),
children: [
TextSpan(
text: '${rod.toY.round()}',
style: TextStyle(
color: rod.color,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
],
);
},
),
touchCallback: (FlTouchEvent event, barTouchResponse) {
setState(() {
if (!event.isInterestedForInteractions ||
barTouchResponse == null ||
barTouchResponse.spot == null) {
touchedIndex = -1;
return;
}
touchedIndex = barTouchResponse.spot!.touchedBarGroupIndex;
});
},
),
柱子样式与动画
通过 BarChartRodData 的属性,我们可以自定义柱子的颜色、宽度和动画效果:
BarChartRodData(
toY: 10,
color: Colors.blue,
width: 20.0,
animationDuration: const Duration(milliseconds: 500),
),
OpenHarmony 适配优化实践
性能优化策略
在 OpenHarmony 设备上,特别是中低端设备,性能优化尤为重要:
-
数据点数量控制:根据屏幕宽度和设备性能,动态调整数据点的数量,避免过多数据点导致渲染卡顿。
-
RepaintBoundary 隔离:使用
RepaintBoundary包裹图表组件,避免图表重绘时影响其他组件的渲染。 -
缓存优化:对于静态图表,可以考虑使用
RepaintBoundary配合GlobalKey进行缓存,减少重复渲染。
手势兼容性保障
OpenHarmony 的手势系统与其他平台可能存在差异,需要特别注意:
-
触摸事件处理:确保
GestureDetector或Listener正确捕获触摸事件,特别是在图表区域。 -
手势冲突:如果图表与其他组件存在手势冲突,需要使用
GestureDetector的behavior属性或GestureRecognizer进行处理。 -
测试验证:在真实的 OpenHarmony 设备上测试各种手势操作,确保交互流畅。
真实设备测试要点
在真实的 OpenHarmony 设备上测试时,需要关注以下几点:
-
渲染性能:观察图表在不同数据量下的渲染速度和流畅度。
-
触摸响应:测试触摸交互的响应速度和准确性。
-
屏幕适配:在不同屏幕尺寸和分辨率的设备上测试,确保图表布局正确。
-
状态恢复:测试应用在后台切换后重新进入时,图表状态是否正确恢复。
-
资源占用:监控应用的内存和 CPU 占用,确保图表不会导致资源消耗过高。
总结
通过本次实践,我们成功在 OpenHarmony 平台上实现了基于 fl_chart 库的柱状图功能。fl_chart 库的高度自定义能力使得我们可以创建美观、交互友好的图表,而 OpenHarmony 的适配过程也相对顺利,主要集中在性能优化和手势兼容性方面。
更多推荐

所有评论(0)