【Flutter for OpenHarmony】训练营 Day 8-11:架构升级——底部导航实现与模块化重构
本教程指导开发者将Flutter项目从Demo升级为工程化应用。重点介绍了底部导航栏实现(使用IndexedStack保持页面状态)、工程目录重构(采用MVC/MVVM分层架构)以及鸿蒙环境下的特殊处理(如返回键管理和生命周期优化)。教程包含实战代码示例,并针对常见问题提供解决方案,包括页面切换数据刷新、路径自动修复等,帮助开发者构建具备商业化App雏形的多页应用。
这份 Day 8-11 的教程标志着你的项目从“Demo”迈向了“工程化”。底部导航与目录重构是大型 App 的地基。为了让这篇教程更具实战参考价值,我建议在状态持久化、鸿蒙原生动效适配、以及模块化深度上进行补充优化。
🎯 核心目标
本阶段我们将告别“单页面”模式,构建一个具备多页切换能力的商业化 App 雏形:
-
多端导航:使用
IndexedStack实现丝滑的 Tab 切换,保留页面滚动状态。 -
结构重构:按照 MVC/MVVM 思想分层,解决代码耦合问题。
-
状态保持:深度解析鸿蒙环境下页面生命周期的管理。
一、 底部导航栏:构建应用“骨架”
1.1 HomePage (Shell) 的设计细节
在鸿蒙系统中,底部导航的交互感非常重要。我们不仅要实现切换,还要确保状态不丢失。
// lib/pages/home_page.dart
class _HomePageState extends State<HomePage> {
int _currentIndex = 0;
// 定义页面列表
final List<Widget> _pages = [
const MemoPage(), // 备忘录列表
const ProfilePage(), // 个人中心
];
@override
Widget build(BuildContext context) {
return Scaffold(
// ✨ 关键点:IndexedStack 能够保持子页面的滚动位置,避免重复加载网络数据
body: IndexedStack(
index: _currentIndex,
children: _pages,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (index) => setState(() => _currentIndex = index),
// 适配鸿蒙风格:使用固定类型,避免 Tab 抖动
type: BottomNavigationBarType.fixed,
selectedItemColor: Theme.of(context).primaryColor,
unselectedItemColor: Colors.grey,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.description_outlined),
activeIcon: Icon(Icons.description),
label: '备忘录',
),
BottomNavigationBarItem(
icon: Icon(Icons.person_outline),
activeIcon: Icon(Icons.person),
label: '我的',
),
],
),
);
}
}
二、 工程重构:从“扁平”到“层级”
随着业务逻辑增加,如果所有文件都在 lib 根目录,维护将变成灾难。
2.1 标准分层规范
推荐采用以下分层结构,这在华为 HarmonyOS 原生开发中也是被推崇的目录逻辑:
| 目录 | 职责 |
lib/models/ |
数据模型:负责 JSON 解析与实体类定义 |
lib/pages/ |
视图层:所有的 UI 页面文件 |
lib/widgets/ |
通用组件:可复用的卡片、按钮、输入框 |
lib/services/ |
服务层:封装 HTTP 请求、数据库操作 |
lib/utils/ |
工具类:日期转换、日志工具、常量定义 |
三、 避坑与进阶指南
3.1 页面切换时的生命周期问题
现象:在使用 IndexedStack 后,虽然页面不再重新销毁(Dispose),但切换 Tab 时,initState 不会再次触发。
解决:如果需要在每次切回页面时刷新数据,可以配合 RouteAware 或者在 onTap 切换时通过全局状态(如 Provider)通知子页面。
3.2 鸿蒙特有的“返回键”处理
在鸿蒙真机上,用户可能会点击硬件/手势返回键。如果不处理,可能会直接退出应用。
优化建议:在 HomePage 外层包裹 PopScope(原 WillPopScope),实现“连续点击两次退出应用”的逻辑。
Dart
return PopScope(
canPop: false,
onPopInvoked: (didPop) {
// 处理双击退出的逻辑
},
child: Scaffold(...),
);
3.3 自动修复 Import 路径
在 VS Code 中移动文件后,如果出现大面积报错:
-
全局搜索替换:利用正则或简单的文本替换。
-
Dart Fix:在终端运行
dart fix --apply,它可以自动修复部分简单的引用错误。
四、 总结
Day 8-11 的工作虽然看起来只是“搬家”和“加个底座”,但这是项目从 Demo 走向产品的必经之路。规范的目录结构能让你的代码在 AtomGit 社区中获得更高的专业评价。
五:目标
本阶段我们将告别“单页面”模式,构建一个具备多页切换能力的商业化 App 雏形:
-
多端导航:使用
IndexedStack实现丝滑的 Tab 切换,保留页面滚动状态。 -
结构重构:按照 MVC/MVVM 思想分层,解决代码耦合问题。
-
状态保持:深度解析鸿蒙环境下页面生命周期的管理。
一、 底部导航栏:构建应用“骨架”
1.1 HomePage (Shell) 的设计细节
在鸿蒙系统中,底部导航的交互感非常重要。我们不仅要实现切换,还要确保状态不丢失。
Dart
// lib/pages/home_page.dart
class _HomePageState extends State<HomePage> {
int _currentIndex = 0;
// 定义页面列表
final List<Widget> _pages = [
const MemoPage(), // 备忘录列表
const ProfilePage(), // 个人中心
];
@override
Widget build(BuildContext context) {
return Scaffold(
// ✨ 关键点:IndexedStack 能够保持子页面的滚动位置,避免重复加载网络数据
body: IndexedStack(
index: _currentIndex,
children: _pages,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (index) => setState(() => _currentIndex = index),
// 适配鸿蒙风格:使用固定类型,避免 Tab 抖动
type: BottomNavigationBarType.fixed,
selectedItemColor: Theme.of(context).primaryColor,
unselectedItemColor: Colors.grey,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.description_outlined),
activeIcon: Icon(Icons.description),
label: '备忘录',
),
BottomNavigationBarItem(
icon: Icon(Icons.person_outline),
activeIcon: Icon(Icons.person),
label: '我的',
),
],
),
);
}
}
二、 工程重构:从“扁平”到“层级”
随着业务逻辑增加,如果所有文件都在 lib 根目录,维护将变成灾难。
2.1 标准分层规范
推荐采用以下分层结构,这在华为 HarmonyOS 原生开发中也是被推崇的目录逻辑:
| 目录 | 职责 |
lib/models/ |
数据模型:负责 JSON 解析与实体类定义 |
lib/pages/ |
视图层:所有的 UI 页面文件 |
lib/widgets/ |
通用组件:可复用的卡片、按钮、输入框 |
lib/services/ |
服务层:封装 HTTP 请求、数据库操作 |
lib/utils/ |
工具类:日期转换、日志工具、常量定义 |
三、 避坑与进阶指南
3.1 页面切换时的生命周期问题
现象:在使用 IndexedStack 后,虽然页面不再重新销毁(Dispose),但切换 Tab 时,initState 不会再次触发。
解决:如果需要在每次切回页面时刷新数据,可以配合 RouteAware 或者在 onTap 切换时通过全局状态(如 Provider)通知子页面。
3.2 鸿蒙特有的“返回键”处理
在鸿蒙真机上,用户可能会点击硬件/手势返回键。如果不处理,可能会直接退出应用。
优化建议:在 HomePage 外层包裹 PopScope(原 WillPopScope),实现“连续点击两次退出应用”的逻辑。
Dart
return PopScope(
canPop: false,
onPopInvoked: (didPop) {
// 处理双击退出的逻辑
},
child: Scaffold(...),
);
3.3 自动修复 Import 路径
在 VS Code 中移动文件后,如果出现大面积报错:
-
全局搜索替换:利用正则或简单的文本替换。
-
Dart Fix:在终端运行
dart fix --apply,它可以自动修复部分简单的引用错误。
更多推荐




所有评论(0)