拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Flutter for OpenHarmony 实战:HarmonyOS ArkTS API 24实现一个柱状图

在移动开发领域我们总是面临着选择与适配。今天你的Flutter应用在Android和iOS上跑得正欢明天可能就需要考虑一个新的平台HarmonyOS鸿蒙。这不是一道选答题而是很多团队正在面对的现实。Flutter的优势很明确——写一套代码就能在两个主要平台上运行开发体验流畅。而鸿蒙代表的是下一个时代的互联生态它不仅仅是手机系统更着眼于未来全场景的体验。将现有的Flutter应用适配到鸿蒙听起来像是一个“跨界”任务但它本质上是一次有价值的技术拓展让产品触达更多用户也让技术栈覆盖更广。不过这条路走起来并不像听起来那么简单。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 实时预览 效果展示运行到鸿蒙虚拟设备中效果展示目录功能代码实现FlHorizontalBarChart 组件实现主页面集成本次开发中容易遇到的问题总结本次开发中用到的技术点功能代码实现FlHorizontalBarChart 组件实现FlHorizontalBarChart 是一个基于 fl_chart 库实现的柱状图组件具有以下特性支持自定义标题和数据实现点击交互效果包含图例说明响应式布局设计核心代码实现importpackage:flutter/material.dart;importpackage:fl_chart/fl_chart.dart;classFlHorizontalBarChartextendsStatefulWidget{finalStringtitle;finalListMapString,dynamicdata;finaldouble?width;finaldouble?height;constFlHorizontalBarChart({Key?key,requiredthis.title,requiredthis.data,this.width,this.height,}):super(key:key);overrideStateFlHorizontalBarChartcreateState()_FlHorizontalBarChartState();}class_FlHorizontalBarChartStateextendsStateFlHorizontalBarChart{int?_touchedIndex;String_clickInfo;// 颜色列表finalListColorcolors[Colors.blue,Colors.green,Colors.orange,Colors.purple,Colors.red,Colors.yellow,Colors.teal,Colors.pink,];void_onBarTap(BarTouchResponse?response){if(response!nullresponse.spot!null){setState((){_touchedIndexresponse.spot!.touchedBarGroupIndex;finaldataItemwidget.data[_touchedIndex!];_clickInfo点击了: ${dataItem[name]} (${dataItem[value]});});// 显示点击信息提示ScaffoldMessenger.of(context).showSnackBar(SnackBar(content:Text(${widget.data[_touchedIndex!][name]}: ${widget.data[_touchedIndex!][value]}),duration:constDuration(seconds:1),),);}}overrideWidgetbuild(BuildContextcontext){// 计算最大值用于Y轴缩放double maxValue0;for(variteminwidget.data){finalvalueitem[value]asdouble???(item[value]asint).toDouble();if(valuemaxValue){maxValuevalue;}}// 向上取整到最近的100的倍数maxValue(maxValue/100).ceil()*100;returnContainer(width:widget.width??double.infinity,height:widget.height??400,margin:constEdgeInsets.all(16),padding:constEdgeInsets.all(16),decoration:BoxDecoration(borderRadius:BorderRadius.circular(8),color:Colors.white,boxShadow:[BoxShadow(color:Colors.grey.withOpacity(0.2),spreadRadius:1,blurRadius:3,offset:constOffset(0,1),),],),child:Column(crossAxisAlignment:CrossAxisAlignment.start,children:[Text(widget.title,style:constTextStyle(fontSize:18,fontWeight:FontWeight.bold,color:Colors.black87,),),constSizedBox(height:16),Expanded(child:BarChart(BarChartData(alignment:BarChartAlignment.spaceAround,barTouchData:BarTouchData(touchCallback:(event,response)_onBarTap(response),enabled:true,touchTooltipData:BarTouchTooltipData(tooltipBgColor:Colors.blueGrey,getTooltipItem:(group,groupIndex,rod,rodIndex){finaldataItemwidget.data[groupIndex];returnBarTooltipItem(${dataItem[name]}: ${dataItem[value]},constTextStyle(color:Colors.white),);},),),titlesData:FlTitlesData(leftTitles:AxisTitles(sideTitles:SideTitles(showTitles:true,getTitlesWidget:(value,meta){if(value.toInt()0value.toInt()widget.data.length){returnText(widget.data[value.toInt()][name],style:constTextStyle(fontSize:12),);}returnconstText();},interval:1,reservedSize:80,),),bottomTitles:AxisTitles(sideTitles:SideTitles(showTitles:true,getTitlesWidget:(value,meta){returnText(\$value,style:constTextStyle(fontSize:12),);},interval:maxValue/5,),),topTitles:constAxisTitles(sideTitles:SideTitles(showTitles:false)),rightTitles:constAxisTitles(sideTitles:SideTitles(showTitles:false)),),gridData:FlGridData(show:true,drawVerticalLine:true,drawHorizontalLine:false,verticalInterval:maxValue/5,),borderData:FlBorderData(show:true,border:constBorder(bottom:BorderSide(),left:BorderSide(),),),maxY:maxValue,barGroups:widget.data.asMap().entries.map((entry){finalindexentry.key;finaldataentry.value;finalvaluedata[value]asdouble???(data[value]asint).toDouble();finalisTouchedindex_touchedIndex;finalbarWidthisTouched?25.0:20.0;returnBarChartGroupData(x:index,barRods:[BarChartRodData(toY:value,color:colors[index%colors.length],width:barWidth,borderRadius:BorderRadius.circular(4),),],);}).toList(),),),),if(_clickInfo.isNotEmpty)Padding(padding:constEdgeInsets.only(top:12),child:Text(_clickInfo,style:constTextStyle(fontSize:14,color:Colors.grey,),),),],),);}}组件参数说明参数类型必填描述titleString是柱状图标题dataListMapString, dynamic是柱状图数据每个元素包含 name 和 value 字段widthdouble?否组件宽度默认充满父容器heightdouble?否组件高度默认 400使用方法FlHorizontalBarChart(title:访问来源分析,data:[{value:335,name:直接访问},{value:310,name:邮件营销},{value:234,name:联盟广告},{value:135,name:视频广告},{value:1548,name:搜索引擎}],)主页面集成主页面使用 MyHomePage 组件实现集成了两个 FlHorizontalBarChart 实例分别展示访问来源分析和产品销售分布数据。核心代码实现importpackage:flutter/material.dart;importpackage:aa/widgets/fl_horizontal_bar_chart.dart;voidmain(){runApp(constMyApp());}classMyAppextendsStatelessWidget{constMyApp({super.key});overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:Flutter for openHarmony,theme:ThemeData(colorScheme:ColorScheme.fromSeed(seedColor:Colors.deepPurple),useMaterial3:true,),debugShowCheckedModeBanner:false,home:constMyHomePage(title:Flutter for openHarmony),);}}classMyHomePageextendsStatefulWidget{constMyHomePage({super.key,requiredthis.title});finalStringtitle;overrideStateMyHomePagecreateState()_MyHomePageState();}class_MyHomePageStateextendsStateMyHomePage{// 柱状图数据finalListMapString,dynamicbarData1[{value:335,name:直接访问},{value:310,name:邮件营销},{value:234,name:联盟广告},{value:135,name:视频广告},{value:1548,name:搜索引擎}];finalListMapString,dynamicbarData2[{value:120,name:A产品},{value:200,name:B产品},{value:150,name:C产品},{value:80,name:D产品},{value:70,name:E产品}];overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text(widget.title),),body:SingleChildScrollView(padding:constEdgeInsets.all(16),child:Column(crossAxisAlignment:CrossAxisAlignment.center,children:Widget[constSizedBox(height:20),// 第一个柱状图FlHorizontalBarChart(title:访问来源分析,data:barData1,),constSizedBox(height:40),// 第二个柱状图FlHorizontalBarChart(title:产品销售分布,data:barData2,),constSizedBox(height:40),constText(交互说明点击柱状图查看详细信息,style:TextStyle(fontSize:16,color:Colors.grey,),),constSizedBox(height:40),],),),);}}本次开发中容易遇到的问题依赖管理问题问题添加 fl_chart 依赖后需要确保依赖版本与 Flutter 版本兼容否则可能导致编译失败或运行时错误解决方案在 pubspec.yaml 中指定合适的 fl_chart 版本如 ^0.64.0并执行flutter pub get命令更新依赖数据格式问题问题柱状图数据中的 value 字段类型需要为 double直接使用 int 类型可能导致类型错误解决方案在构建 BarChartRodData 时对 int 类型的 value 进行类型转换如(value as int).toDouble()布局适配问题问题在不同屏幕尺寸下柱状图和标签的布局可能出现异常特别是在小屏幕设备上解决方案使用 Expanded 组件和响应式布局确保在不同屏幕尺寸下的良好显示效果同时为组件提供可自定义的宽高参数交互响应问题问题使用 fl_chart 库时BarTouchData 的 touchCallback 方法签名与预期不符可能导致编译错误解决方案使用适配的回调方式通过匿名函数转换参数格式确保回调函数能正确接收和处理事件参数Y轴刻度计算问题问题柱状图的 Y 轴刻度需要根据数据最大值动态计算否则可能导致刻度显示不合理解决方案遍历数据计算最大值然后向上取整到合适的刻度值确保所有数据都能在图表中完整显示总结本次开发中用到的技术点Flutter 状态管理使用 StatefulWidget 和 setState 管理组件状态实现柱状图点击交互效果通过状态变量 _touchedIndex 跟踪当前点击的柱状图Flutter 布局系统使用 Container、Column、Expanded 等布局组件构建响应式界面运用 BoxDecoration 实现卡片阴影效果提升视觉体验fl_chart 图表库基于 fl_chart 库实现柱状图渲染配置 BarChartData、BarChartGroupData 等参数实现自定义柱状图效果使用 BarTouchData 实现柱状图点击交互和提示信息数据处理使用 ListMapString, dynamic 存储和管理柱状图数据实现数据最大值计算和 Y 轴刻度动态调整用户交互实现柱状图点击事件处理显示详细信息使用 ScaffoldMessenger 显示 SnackBar 提示信息代码组织采用组件化开发方式将柱状图封装为独立的 FlHorizontalBarChart 组件分离业务逻辑和 UI 展示提高代码可维护性跨平台适配选择跨平台兼容性好的 fl_chart 库避免平台特定依赖确保代码在 Flutter 支持的所有平台包括 OpenHarmony上正常运行
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门