Flutter for OpenHarmony 实战:树形结构数据展示:基于HarmonyOS API 24 使用 Expandable或 tree_view库,或递归构建 ListView。
前言:跨生态开发的新机遇
在移动开发领域,我们总是面临着选择与适配。今天,你的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 实时预览 效果展示

运行到鸿蒙虚拟设备中效果展示
功能代码实现
树形结构组件
组件结构设计
树形结构组件采用了清晰的分层设计,主要包含以下核心部分:
- 数据模型:使用 TreeNode 类定义树形节点结构
- 树形组件:使用 TreeView 组件实现树形结构的渲染和交互
- 示例数据:提供公司组织架构的示例数据,展示组件的实际应用
- 状态管理:使用 setState 管理节点的展开/折叠状态
核心代码实现
数据模型定义
class TreeNode {
final String title;
final List<TreeNode>? children;
bool isExpanded;
TreeNode({
required this.title,
this.children,
this.isExpanded = false,
});
}
树形组件实现
class TreeView extends StatefulWidget {
final List<TreeNode> nodes;
final Function(TreeNode)? onTap;
const TreeView({
Key? key,
required this.nodes,
this.onTap,
}) : super(key: key);
State<TreeView> createState() => _TreeViewState();
}
class _TreeViewState extends State<TreeView> {
Widget build(BuildContext context) {
return ListView.builder(
itemCount: widget.nodes.length,
itemBuilder: (context, index) {
return _buildTreeNode(widget.nodes[index], 0);
},
);
}
Widget _buildTreeNode(TreeNode node, int level) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
onTap: () {
setState(() {
node.isExpanded = !node.isExpanded;
});
if (widget.onTap != null) {
widget.onTap!(node);
}
},
child: Container(
padding: EdgeInsets.only(
left: 20.0 * level,
top: 12.0,
bottom: 12.0,
right: 16.0,
),
child: Row(
children: [
if (node.children != null && node.children!.isNotEmpty)
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Icon(
node.isExpanded ? Icons.expand_less : Icons.expand_more,
size: 18.0,
color: Colors.blue,
),
),
Expanded(
child: Text(
node.title,
style: TextStyle(
fontSize: 16.0,
fontWeight: level == 0 ? FontWeight.bold : FontWeight.normal,
),
),
),
],
),
),
),
if (node.isExpanded && node.children != null)
for (var child in node.children!)
_buildTreeNode(child, level + 1),
],
);
}
}
示例数据与使用
class TreeViewExample extends StatelessWidget {
final List<TreeNode> _sampleData = [
TreeNode(
title: '公司总部',
children: [
TreeNode(
title: '技术部',
children: [
TreeNode(title: '前端开发'),
TreeNode(title: '后端开发'),
TreeNode(title: '测试团队'),
],
),
TreeNode(
title: '市场部',
children: [
TreeNode(title: '品牌推广'),
TreeNode(title: '销售团队'),
],
),
TreeNode(
title: '人力资源部',
children: [
TreeNode(title: '招聘组'),
TreeNode(title: '培训组'),
],
),
],
),
TreeNode(
title: '分公司',
children: [
TreeNode(title: '北京分公司'),
TreeNode(title: '上海分公司'),
TreeNode(title: '广州分公司'),
],
),
TreeNode(
title: '合作伙伴',
children: [
TreeNode(title: '供应商'),
TreeNode(title: '客户'),
],
),
];
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(16.0),
child: TreeView(
nodes: _sampleData,
onTap: (node) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('点击了: ${node.title}')),
);
},
),
),
);
}
}
主页面集成
在 main.dart 文件中集成树形结构组件:
import 'package:flutter/material.dart';
import 'components/tree_view.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter for openHarmony',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
debugShowCheckedModeBanner: false,
home: const MyHomePage(title: 'Flutter for openHarmony'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('树形结构数据展示'),
centerTitle: true,
backgroundColor: Colors.blue,
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: TreeViewExample(),
),
);
}
}
使用方法
- 导入组件:在需要使用的文件中导入树形结构组件
- 创建数据:使用 TreeNode 类创建树形结构数据
- 添加到布局:将 TreeView 组件添加到页面布局中
- 配置回调:可选地配置 onTap 回调函数,处理节点点击事件
开发注意事项
- 递归深度:注意控制树形结构的递归深度,避免过深导致性能问题
- 数据量:对于大量数据的树形结构,考虑使用虚拟化列表或分页加载
- 状态管理:对于复杂的树形结构,考虑使用 Provider 或 Bloc 等状态管理方案
- UI适配:确保树形结构在不同屏幕尺寸下都能正常显示
- 交互体验:添加适当的动画效果,提升用户交互体验
开发中容易遇到的问题
1. 递归渲染性能问题
问题:当树形结构层级较深或节点数量较多时,可能会出现渲染性能问题
解决方案:
- 控制递归深度,避免无限层级的渲染
- 对于大型树形结构,考虑使用懒加载方式
- 优化 build 方法,避免不必要的重建
2. 状态管理混乱
问题:当树形结构复杂时,节点的展开/折叠状态管理可能变得混乱
解决方案:
- 使用统一的状态管理方案
- 将状态逻辑封装在组件内部
- 考虑使用不可变数据结构管理状态
3. 点击事件处理
问题:在树形结构中,点击事件的传递和处理可能会出现问题
解决方案:
- 正确使用 InkWell 或 GestureDetector 处理点击事件
- 确保事件处理函数能够正确识别点击的节点
- 避免事件冲突和冒泡问题
4. 布局溢出问题
问题:当树形结构层级较深时,左侧缩进可能导致布局溢出
解决方案:
- 设置合理的缩进值
- 使用 ScrollView 包裹树形结构
- 考虑使用水平滚动处理深层级缩进
5. 数据加载问题
问题:对于动态加载的树形结构,数据加载和状态同步可能会出现问题
解决方案:
- 实现异步数据加载逻辑
- 添加加载状态指示器
- 处理数据加载失败的情况
总结开发中用到的技术点

1. 数据结构设计
- TreeNode 类:自定义树形节点数据结构,支持递归嵌套
- 属性设计:包含标题、子节点列表和展开状态等核心属性
- 构造函数:提供灵活的构造函数,支持可选参数
2. 组件开发
- StatefulWidget:使用有状态组件管理树形结构的展开/折叠状态
- ListView.builder:使用列表构建器高效渲染树形结构
- 递归渲染:通过递归调用 _buildTreeNode 方法实现无限层级渲染
- 条件渲染:根据节点状态和层级条件渲染不同的UI元素
3. 交互设计
- InkWell:添加点击交互效果,响应用户操作
- Icon 切换:根据节点展开状态切换不同的图标
- SnackBar:显示节点点击反馈,增强用户体验
- 缩进设计:根据节点层级设置不同的缩进,清晰展示树形结构
4. 样式设计
- 字体样式:为不同层级的节点设置不同的字体权重,增强视觉层次感
- 间距设计:合理设置节点间距,提升可读性
- 颜色方案:使用统一的颜色方案,保持视觉一致性
5. 性能优化
- 按需渲染:只渲染展开节点的子节点,减少渲染压力
- 状态管理:使用 setState 局部更新状态,避免全局重建
- 布局优化:使用 Expanded 和 Container 优化布局结构
6. 跨平台适配
- Flutter 跨平台:代码可在 Android、iOS 和 OpenHarmony 平台运行
- 响应式布局:适配不同屏幕尺寸和设备类型
- 平台兼容性:确保使用的 Flutter API 在 OpenHarmony 平台上可用
通过以上技术点的应用,我们成功实现了树形结构数据展示功能,为用户提供了直观、交互性强的树形数据浏览体验。树形结构组件的设计和实现充分考虑了性能、可扩展性和用户体验,为后续的功能迭代和优化奠定了良好的基础。
更多推荐


所有评论(0)