【Flutter for OpenHarmony】鸿蒙跨平台训练营 Day 8-11: 底部导航与工程结构优化
通过今天的实战,我们将一个简单的单页面应用升级为了具备标准导航结构的多页面应用,并规范了代码组织结构。这为后续添加更多功能模块(如详情页、设置页)打下了良好的基础。项目仓库:https://gitcode.com/shhzxt/flutter_OpenHarmony欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net。
·
Day 8-11: 底部导航与工程结构优化
在完成了基础的网络列表功能后,我们将进一步完善应用的架构,添加底部导航栏以支持多页面切换,并对项目文件进行模块化重构,使其更符合工程化标准。
一、 底部导航栏实现
我们通过引入 BottomNavigationBar 组件,实现了“备忘录”和“我的”两个功能模块的切换。
1.1 新建 Home 页 (Shell 模式)
为了管理多个页面的切换状态,我们创建了一个 HomePage 作为应用的“外壳”。
- 文件路径:
lib/pages/home_page.dart - 核心逻辑:
- 使用
IndexedStack包裹子页面列表,确保切换页面时保留原页面的滚动位置和输入状态(懒加载模式)。 BottomNavigationBar管理底部 Tab 的选中状态与点击事件。
- 使用
class _HomePageState extends State<HomePage> {
int _currentIndex = 0; // 当前选中索引
// 页面集合
final List<Widget> _pages = [
const MemoPage(), // 备忘录列表页
const ProfilePage(), // 个人中心页
];
Widget build(BuildContext context) {
return Scaffold(
// 使用 IndexedStack 保持页面状态
body: IndexedStack(
index: _currentIndex,
children: _pages,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
type: BottomNavigationBarType.fixed, // 固定模式,适合 2-4 个 Tab
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.note_alt_outlined), // 未选中图标
activeIcon: Icon(Icons.note_alt), // 选中图标
label: '备忘录',
),
BottomNavigationBarItem(
icon: Icon(Icons.person_outline),
activeIcon: Icon(Icons.person),
label: '我的',
),
],
),
);
}
}

1.2 新建个人中心页
创建一个简单的静态页面用于展示用户信息。
- 文件路径:
lib/pages/profile_page.dart
class ProfilePage extends StatelessWidget {
const ProfilePage({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('我的'), centerTitle: true),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const CircleAvatar(radius: 50, child: Icon(Icons.person, size: 50)),
const SizedBox(height: 16),
const Text('User Name', style: TextStyle(fontSize: 24)),
],
),
),
);
}
}

后续我们会在这个页面实现登录及新增备忘录功能
1.3 更新入口文件
修改 main.dart,将 home 属性指向新的 HomePage。
// lib/main.dart
import 'pages/home_page.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
// ...
Widget build(BuildContext context) {
return MaterialApp(
// ...
home: const HomePage(), // 入口指向 HomePage
);
}
}
二、 工程结构重构
随着文件数量增加,扁平化的目录结构已不再适用。我们对 lib 目录进行了标准的模块化分层。
2.1 目录结构调整
lib/
├── models/ # 数据模型层
│ └── memo_model.dart
├── pages/ # 页面 UI 层
│ ├── home_page.dart
│ ├── memo_page.dart
│ ├── post_page.dart
│ └── profile_page.dart
└── main.dart # 程序入口
2.2 引用路径修复
文件移动后,Dart 的 import 路径会报错,需要逐一修复。
- main.dart:
import 'memo_page.dart'->import 'pages/home_page.dart'
- pages/memo_page.dart:
import 'memo_model.dart'->import '../models/memo_model.dart'(使用相对路径访问上一级目录)
三、 遇到的问题与解决方案
3.1 编译报错:找不到构造函数 ‘HomePage’
- 现象: 修改
main.dart后,编译器提示Error: Couldn't find constructor 'HomePage'。 - 原因: 虽然代码中写了
home: const HomePage(),但忘记引入home_page.dart文件,或者引入路径错误。 - 解决:
- 检查文件头部是否包含
import 'pages/home_page.dart';。 - 确保
HomePage类是public的(类名不以_开头)。
- 检查文件头部是否包含
3.2 页面状态丢失
- 现象: 在“备忘录”页面下拉刷新了一半,切换到“我的”,再切回来,刷新状态没了,或者滚动条回到了顶部。
- 原因: 如果直接在
body中使用条件判断切换 Widget (如_pages[_currentIndex]),每次切换都会导致组件销毁和重建。 - 解决: 使用
IndexedStack组件包裹所有子页面。它会一次性构建所有子 Widget,但在视图层级上只显示当前索引的 Widget,从而保留其他页面的内存状态。
3.3 文件移动后大量爆红
- 现象: 手动移动文件到
pages目录后,几乎所有文件都报错。 - 解决:
- VS Code 技巧:在移动文件时,尽量使用 IDE 的重构功能(Refactor -> Move),它会自动更新引用路径。
- 如果手动移动,需重点检查
import路径,特别是相对路径 (../) 的层级是否正确。
四、 总结
通过今天的实战,我们将一个简单的单页面应用升级为了具备标准导航结构的多页面应用,并规范了代码组织结构。这为后续添加更多功能模块(如详情页、设置页)打下了良好的基础。
项目仓库:https://gitcode.com/shhzxt/flutter_OpenHarmony
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)