Flutter 如何为所有页面配置共用的Bottom Navigation Bar
Flutter全页面共用底部导航栏实现方案
- 核心逻辑:不要给每个页面单独配置BottomNavigationBar,也不要用根路由跳转页面。将底部导航栏作为上层固定组件,所有业务页面都在下层的嵌套路由容器中渲染,即可保证底部导航栏始终在最上层不被覆盖。
- 第一步:配置全局导航状态
用ValueNotifier、Provider或其他状态管理工具存储当前选中的底部导航索引,避免组件嵌套传参的冗余,示例代码:final currentNavIndex = ValueNotifier<int>(0); // 四个主导航页对应独立的导航key,用来控制各自的路由栈 final List<GlobalKey<NavigatorState>> navKeys = List.generate(4, (_) => GlobalKey()); - 第二步:封装根导航容器
根容器使用Scaffold,固定bottomNavigationBar为你的公共底部导航组件,body使用IndexedStack嵌套四个独立的Navigator路由栈,每个路由栈对应一个底部导航项的页面分支:class RootNavContainer extends StatelessWidget { const RootNavContainer({super.key}); @override Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: currentNavIndex, builder: (context, index, child) { return Scaffold( body: IndexedStack( index: index, children: List.generate(4, (i) => _buildNavStack(i)), ), bottomNavigationBar: _buildYourBottomNav(), // 替换成你自己的底部导航组件 ); }, ); } Widget _buildNavStack(int navIndex) { return Navigator( key: navKeys[navIndex], onGenerateRoute: (settings) { // 这里配置对应导航分支的所有页面路由,包括主导航页和其他子页面 Widget page; switch(settings.name) { case '/': page = getMainPageByIndex(navIndex); // 替换成四个主导航页的实例 break; // 配置所有其他子页面的路由映射 case '/goodsDetail': page = const GoodsDetailPage(); break; case '/userSettings': page = const UserSettingsPage(); break; default: page = const NotFoundPage(); } return MaterialPageRoute(builder: (context) => page); }, ); } } - 第三步:修改页面跳转逻辑
所有页面跳转不要调用Navigator.of(context),改为调用当前导航分支的Navigator实例:// 跳转子页面示例 navKeys[currentNavIndex.value].currentState?.pushNamed('/goodsDetail'); // 返回上一页示例 navKeys[currentNavIndex.value].currentState?.pop(); - 可选交互优化
点击底部导航项时,如果当前点击的是已经选中的导航项,可以调用对应导航栈的popUntil方法回到该分支的根页面,符合主流应用的交互习惯。
注意:根MaterialApp的home直接设置为RootNavContainer即可,不要配置根路由表,所有业务路由都放到各个分支的嵌套Navigator中配置,避免根路由跳转覆盖底部导航栏。
内容的提问来源于stack exchange,提问作者Alex Aung
相关产品推荐
相关产品推荐

