Flutter for OpenHarmony 实战:加载弹窗实现
Flutter 核心概念Widget 体系:使用 StatelessWidget 和 StatefulWidget 构建应用界面布局组件:使用 Center、Column、SizedBox 等布局组件组织界面结构Material 组件:使用 ElevatedButton、Scaffold、AppBar 等 Material 组件构建符合 Material Design 规范的界面Overlay 机
前言:跨生态开发的新机遇
在移动开发领域,我们总是面临着选择与适配。今天,你的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 实时预览 效果展示
运行到鸿蒙虚拟设备中效果展示
功能代码实现
LoadingOverlay 组件开发
组件设计思路
LoadingOverlay 组件是一个独立的加载弹窗工具类,采用静态方法设计模式,方便在应用的任何地方调用。该组件通过 Flutter 的 Overlay 机制实现,能够在界面顶层显示加载状态,支持自定义加载文字、颜色等样式。
核心实现代码
import 'package:flutter/material.dart';
class LoadingOverlay {
static OverlayEntry? _overlayEntry;
static bool _isVisible = false;
static void show(
BuildContext context,
{
String message = '加载中...',
Color backgroundColor = Colors.black54,
Color indicatorColor = Colors.white,
Color textColor = Colors.white,
double fontSize = 14.0,
}
) {
// 如果已经有加载弹窗在显示,先移除
if (_isVisible) {
hide();
}
// 创建覆盖层条目
_overlayEntry = OverlayEntry(
builder: (BuildContext context) {
return Material(
color: Colors.transparent,
child: Container(
color: backgroundColor,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(indicatorColor),
),
const SizedBox(height: 16),
Text(
message,
style: TextStyle(
color: textColor,
fontSize: fontSize,
),
),
],
),
),
),
);
},
);
// 添加覆盖层条目到当前上下文的覆盖层
Overlay.of(context).insert(_overlayEntry!);
_isVisible = true;
}
static void hide() {
if (_isVisible && _overlayEntry != null) {
_overlayEntry?.remove();
_overlayEntry = null;
_isVisible = false;
}
}
}
组件使用方法
LoadingOverlay 组件提供了简洁的静态方法 show 和 hide,可以在应用的任何地方调用,示例如下:
- 显示默认加载弹窗
LoadingOverlay.show(
context,
);
- 显示自定义加载弹窗
LoadingOverlay.show(
context,
message: '正在加载数据...',
backgroundColor: Colors.black54,
indicatorColor: Colors.blue,
textColor: Colors.white,
fontSize: 16.0,
);
- 隐藏加载弹窗
LoadingOverlay.hide();
开发注意事项
-
Overlay 管理:
- 每次显示新的加载弹窗前,需要先检查是否已有弹窗在显示,如果有则先移除,避免多个弹窗叠加显示
- 使用静态变量
_overlayEntry和_isVisible来管理弹窗的显示状态
-
参数设计:
- 提供了丰富的可选参数,包括加载文字、背景颜色、指示器颜色、文字颜色和字体大小
- 为所有可选参数设置了合理的默认值,方便快速调用
-
用户交互:
- 加载弹窗显示时,会覆盖整个屏幕,用户无法操作底层界面,这是加载弹窗的预期行为
-
内存管理:
- 确保在不需要加载弹窗时,调用
hide()方法正确移除 OverlayEntry,避免内存泄漏
- 确保在不需要加载弹窗时,调用
主页面集成与使用
页面结构
主页面 MyHomePage 是一个简单的布局,包含一个按钮,点击后触发加载弹窗,显示3秒后自动隐藏。
核心实现代码
import 'package:flutter/material.dart';
import 'widgets/loading_overlay.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> {
// 模拟加载操作
Future<void> _simulateLoading() async {
// 显示加载弹窗
LoadingOverlay.show(
context,
message: '正在加载数据...',
);
// 模拟网络请求延迟
await Future.delayed(const Duration(seconds: 3));
// 隐藏加载弹窗
LoadingOverlay.hide();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: _simulateLoading,
child: const Text('点击触发加载弹窗'),
),
const SizedBox(height: 20),
const Text(
'加载弹窗将显示3秒后自动隐藏',
style: TextStyle(
fontSize: 16,
color: Colors.grey,
),
),
],
),
),
);
}
}
使用注意事项
-
导入组件:
- 需要在主页面中导入 LoadingOverlay 组件:
import 'widgets/loading_overlay.dart';
- 需要在主页面中导入 LoadingOverlay 组件:
-
Context 传递:
- 调用
LoadingOverlay.show()方法时,需要传递当前的 BuildContext
- 调用
-
异步操作:
- 加载弹窗通常用于异步操作,如网络请求、文件加载等
- 在异步操作完成后,一定要调用
LoadingOverlay.hide()隐藏弹窗
-
用户体验:
- 为加载弹窗设置合适的提示文字,让用户了解当前的加载内容
- 避免加载时间过长,必要时可以添加取消按钮
本次开发中容易遇到的问题
-
Overlay 管理问题
- 问题:多次快速点击按钮时,可能会导致多个加载弹窗叠加显示,或者弹窗显示异常
- 解决方案:在显示新弹窗前,先检查是否已有弹窗在显示,如果有则先移除,使用静态变量来管理弹窗的显示状态
-
内存泄漏问题
- 问题:如果加载弹窗没有正确移除,可能会导致内存泄漏
- 解决方案:确保在异步操作完成后,无论成功还是失败,都调用
hide()方法正确移除 OverlayEntry 并重置状态变量
-
Context 问题
- 问题:在某些情况下,传递的 BuildContext 可能已经失效,导致 Overlay.of(context) 报错
- 解决方案:确保传递的 BuildContext 是有效的,避免在已经 dispose 的 widget 中调用 show 方法
-
样式定制问题
- 问题:不同应用可能需要不同样式的加载弹窗,直接修改组件代码会影响其他地方的使用
- 解决方案:通过参数化设计,提供丰富的可选参数,支持用户自定义样式
-
测试问题
- 问题:在自动化测试中,加载弹窗可能会干扰测试流程
- 解决方案:可以添加一个测试模式,在测试环境中禁用加载弹窗的显示
总结本次开发中用到的技术点
-
Flutter 核心概念
- Widget 体系:使用 StatelessWidget 和 StatefulWidget 构建应用界面
- 布局组件:使用 Center、Column、SizedBox 等布局组件组织界面结构
- Material 组件:使用 ElevatedButton、Scaffold、AppBar 等 Material 组件构建符合 Material Design 规范的界面
-
Overlay 机制
- 使用 Flutter 的 Overlay 系统在界面顶层显示悬浮组件
- 通过 OverlayEntry 管理悬浮组件的创建、插入和移除
-
静态工具类设计
- 采用静态方法和静态变量设计 LoadingOverlay 工具类,方便全局调用
- 使用私有静态变量管理组件状态,确保组件行为的一致性
-
参数化设计
- 使用命名可选参数和默认值,提高组件的灵活性和易用性
- 支持自定义多个样式参数,满足不同场景的需求
-
异步编程
- 使用 Future.delayed 模拟网络请求延迟
- 在异步操作中管理加载弹窗的显示和隐藏
-
组件化开发
- 将加载弹窗功能抽离为独立的组件,提高代码的可复用性和可维护性
- 遵循单一职责原则,使组件功能明确、易于理解和测试
-
代码组织
- 按功能模块组织代码,将组件放在 widgets 目录下
- 使用清晰的命名和注释,提高代码的可读性
-
用户体验设计
- 通过加载弹窗提供视觉反馈,增强用户体验
- 为加载弹窗设置合适的提示文字和显示时间
通过本次开发,我们实现了一个功能完整、使用灵活的加载弹窗组件,并在主页面中进行了集成和展示。这个组件不仅可以在 Flutter 应用中使用,也可以在 Flutter for OpenHarmony 项目中无缝运行,展示了 Flutter 跨平台开发的优势。
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)