Flutter 三方库 syncfusion_flutter_charts 适配 OpenHarmony ———实现 甜甜圈图表
text: '水果销售分布',),),通过本次开发,我们成功实现了在 Flutter 项目中使用 Syncfusion Flutter Charts 库创建甜甜圈图,并将其适配到 OpenHarmony 平台。Syncfusion Flutter Charts 提供了丰富的配置选项和良好的跨平台兼容性,使得开发者可以轻松创建专业、美观的图表。交互式图表:添加手势操作,如缩放、平移等动态数据更新:实
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net
引言
在移动应用开发中,数据可视化已经成为不可或缺的功能。无论是金融分析、健康追踪还是业务报表,图表都能直观地展示数据趋势和关系。Flutter 作为跨平台开发框架,为开发者提供了一套统一的代码库,可在 iOS、Android、Web 等多个平台运行。随着 OpenHarmony 生态的快速发展,如何将现有的 Flutter 图表库适配到 OpenHarmony 平台成为了一个新的挑战。
Syncfusion Flutter Charts 是 Flutter 生态中一款功能强大的图表库,以其高度自定义能力、丰富的图表类型和专业的视觉效果著称。它支持多种图表类型,包括线图、柱状图、饼图、甜甜圈图等,并且提供了丰富的配置选项,让开发者可以根据需求创建各种复杂的图表。
混合工程结构深度解析
项目目录架构
当Flutter项目集成鸿蒙支持后,典型的项目结构会发生显著变化。以下是经过ohos_flutter插件初始化后的项目结构:
fluuter_openHarmony/
├── lib/ # Flutter业务代码(基本不变)
│ ├── main.dart # 应用入口
├── pubspec.yaml # Flutter依赖配置
├── ohos/ # 鸿蒙原生层(核心适配区)
│ ├── entry/ # 主模块
│ │ └── src/main/
│ │ ├── ets/ # ArkTS代码
│ │ │ ├── entryability/
│ │ │ │ └── EntryAbility.ets # 主Ability
│ │ │ └── pages/
│ │ │ └── Index.ets # 主页面
│ │ ├── resources/ # 鸿蒙资源文件
│ │ │ ├── base/
│ │ │ │ ├── element/ # 字符串等
│ │ │ │ ├── media/ # 图片资源
│ │ │ │ └── profile/ # 配置文件
│ │ └── module.json5 # 应用核心配置
│ ├── AppScope/ # 应用全局配置
│ │ └── resources/
│ │ └── base/
│ │ ├── element/
│ │ └── media/
│ ├── build-profile.json5 # 构建配置
│ └── oh-package.json5 # 鸿蒙依赖管理
└── README.md
展示效果图片
flutter 实时预览 效果展示
运行到鸿蒙虚拟设备中效果展示
依赖配置
具体配置方法
-
添加依赖:在
pubspec.yaml文件中添加 Syncfusion Flutter Charts 依赖dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.8 syncfusion_flutter_charts: ^26.1.39 -
安装依赖:执行
flutter pub get命令安装依赖flutter pub get -
导入包:在需要使用图表的文件中导入包
import 'package:syncfusion_flutter_charts/charts.dart';
配置中遇到的问题和解决方案
-
依赖版本冲突
- 问题:当项目中存在其他依赖与 Syncfusion Flutter Charts 版本不兼容时
- 解决方案:执行
flutter pub upgrade命令更新所有依赖到兼容版本,或在pubspec.yaml中指定兼容的版本范围
-
构建失败
- 问题:在 OpenHarmony 平台上构建时出现依赖解析失败
- 解决方案:确保 Flutter SDK 版本 >= 3.18.0,并且 ohos_flutter 插件版本与当前 Flutter 版本兼容
甜甜圈图实现
实现方法
-
数据模型设计
class PieData { final String category; final double value; final Color color; PieData(this.category, this.value, this.color); } -
数据准备
List<PieData> getPieData() { return [ PieData('苹果', 35, Colors.red), PieData('香蕉', 25, Colors.yellow), PieData('橙子', 20, Colors.orange), PieData('葡萄', 15, Colors.purple), PieData('其他', 5, Colors.grey), ]; } -
图表实现
SizedBox( height: 400, child: SfCircularChart( title: ChartTitle(text: '水果销售分布'), tooltipBehavior: _tooltipBehavior, series: <CircularSeries>[// 甜甜圈图 DoughnutSeries<PieData, String>( dataSource: _chartData, xValueMapper: (PieData data, _) => data.category, yValueMapper: (PieData data, _) => data.value, pointColorMapper: (PieData data, _) => data.color, dataLabelSettings: const DataLabelSettings( isVisible: true, labelPosition: ChartDataLabelPosition.inside, ), // 甜甜圈图特有属性 innerRadius: '60%', radius: '80%', ), ], legend: const Legend( isVisible: true, position: LegendPosition.bottom, ), ), ); -
完整代码实现
import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_charts/charts.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); Widget build(BuildContext context) { return MaterialApp( title: 'Flutter 甜甜圈图演示', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), debugShowCheckedModeBanner: false, home: const MyHomePage(title: 'Flutter 甜甜圈图演示'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; State<MyHomePage> createState() => _MyHomePageState(); } class PieData { final String category; final double value; final Color color; PieData(this.category, this.value, this.color); } class _MyHomePageState extends State<MyHomePage> { late List<PieData> _chartData; late TooltipBehavior _tooltipBehavior; void initState() { _chartData = getPieData(); _tooltipBehavior = TooltipBehavior(enable: true); super.initState(); } List<PieData> getPieData() { return [ PieData('苹果', 35, Colors.red), PieData('香蕉', 25, Colors.yellow), PieData('橙子', 20, Colors.orange), PieData('葡萄', 15, Colors.purple), PieData('其他', 5, Colors.grey), ]; } Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ const Text( '水果销售占比', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), const SizedBox(height: 20), SizedBox( height: 400, child: SfCircularChart( title: ChartTitle(text: '水果销售分布'), tooltipBehavior: _tooltipBehavior, series: <CircularSeries>[// 甜甜圈图 DoughnutSeries<PieData, String>( dataSource: _chartData, xValueMapper: (PieData data, _) => data.category, yValueMapper: (PieData data, _) => data.value, pointColorMapper: (PieData data, _) => data.color, dataLabelSettings: const DataLabelSettings( isVisible: true, labelPosition: ChartDataLabelPosition.inside, ), // 甜甜圈图特有属性 innerRadius: '60%', radius: '80%', ), ], legend: const Legend( isVisible: true, position: LegendPosition.bottom, ), ), ), ], ), ), ), ); } }
实现中遇到的问题和解决方案
-
图表显示不完整
- 问题:在部分设备上,图表可能显示不完整或被截断
- 解决方案:使用
SizedBox为图表指定固定的高度和宽度,确保图表有足够的空间显示
-
颜色配置
- 问题:默认颜色可能不符合设计需求
- 解决方案:通过
pointColorMapper属性自定义每个数据点的颜色,实现个性化的视觉效果
-
数据标签显示
- 问题:数据标签可能重叠或显示位置不当
- 解决方案:调整
dataLabelSettings中的labelPosition属性,选择合适的标签位置
高度自定义配置详解
图表标题配置
title: ChartTitle(
text: '水果销售分布',
textStyle: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
alignment: ChartAlignment.near,
),
图例配置
legend: Legend(
isVisible: true,
position: LegendPosition.bottom,
orientation: LegendItemOrientation.horizontal,
legendItemBuilder: (String name, dynamic series, dynamic point, int index) {
return Container(
padding: const EdgeInsets.all(5),
child: Row(
children: [
Container(
width: 10,
height: 10,
color: _chartData[index].color,
),
const SizedBox(width: 5),
Text(name),
],
),
);
},
),
工具提示配置
tooltipBehavior: TooltipBehavior(
enable: true,
format: 'point.x: point.y%',
tooltipPosition: TooltipPosition.pointer,
canShowMarker: true,
borderWidth: 1,
borderColor: Colors.grey,
),
甜甜圈图特有配置
DoughnutSeries<PieData, String>(
// 其他配置...
innerRadius: '60%', // 内圆半径
radius: '80%', // 外圆半径
startAngle: 90, // 起始角度
endAngle: 360, // 结束角度
explode: true, // 是否突出显示点击的扇区
explodeIndex: 0, // 默认突出显示的扇区索引
explodeOffset: '10%', // 突出显示的偏移量
),
OpenHarmony 适配优化实践
性能优化
- 减少重绘:使用
const构造函数和const变量,减少不必要的重绘 - 懒加载:对于复杂图表,考虑使用
FutureBuilder或StreamBuilder进行懒加载 - 数据处理:在数据量较大时,考虑在后台线程处理数据,避免阻塞 UI 线程
布局适配
-
响应式布局:使用
MediaQuery获取屏幕尺寸,动态调整图表大小final screenWidth = MediaQuery.of(context).size.width; final chartHeight = screenWidth * 0.8; SizedBox( height: chartHeight, child: SfCircularChart( // 配置... ), ); -
安全区域适配:使用
SafeArea确保图表在不同设备上都能正常显示SafeArea( child: Scaffold( // 内容... ), );
平台特定代码
-
条件导入:根据平台导入不同的代码
import 'dart:io'; if (Platform.isAndroid) { // Android 特定代码 } else if (Platform.isIOS) { // iOS 特定代码 } else if (Platform.isWindows) { // Windows 特定代码 } -
平台检测:使用
Platform类检测当前平台if (Platform.isHarmony) { // OpenHarmony 特定代码 }
构建和部署
-
构建命令:
# 构建 OpenHarmony 版本 flutter build ohos # 构建 Web 版本 flutter build web -
部署到设备:
# 运行到 OpenHarmony 设备 flutter run -d ohos
展示效果
Flutter 实时预览效果
在 Flutter 开发环境中,通过热重载功能可以实时预览甜甜圈图的效果。图表会根据数据变化实时更新,便于开发者快速调整和优化。
OpenHarmony 设备运行效果
在 OpenHarmony 设备上运行时,甜甜圈图能够保持与 Flutter 预览一致的视觉效果,包括颜色、动画和交互体验。图表会根据设备屏幕大小自动适配,确保在不同尺寸的设备上都能正常显示。
总结与展望
通过本次开发,我们成功实现了在 Flutter 项目中使用 Syncfusion Flutter Charts 库创建甜甜圈图,并将其适配到 OpenHarmony 平台。Syncfusion Flutter Charts 提供了丰富的配置选项和良好的跨平台兼容性,使得开发者可以轻松创建专业、美观的图表。
未来,我们可以进一步探索 Syncfusion Flutter Charts 的其他功能,如:
- 交互式图表:添加手势操作,如缩放、平移等
- 动态数据更新:实现实时数据更新和动画效果
- 复合图表:将多种图表类型组合使用,如饼图与线图结合
- 主题定制:根据应用主题动态调整图表样式
通过不断优化和扩展,我们可以为用户提供更加丰富、直观的数据可视化体验,满足不同场景下的需求。
更多推荐


所有评论(0)