使用go_router搭配BottomNavigationWidget时非调试模式导航失效
问题分析与解决方案
问题根源
你的代码存在三个核心问题导致非调试模式导航失效:
- 导航方式混用:底部导航中
Product项用了router.go('/product'),其他项用context.go,非调试模式下router实例的上下文绑定可能出现异常,导致导航不生效。 - 页面重复嵌入底部导航:每个页面(Home/Product等)都单独添加了
BottomNavigationWidget,切换页面时会重建整个Scaffold,破坏了go_router的路由栈逻辑。 - 未使用ShellRoute管理底部导航:go_router实现底部导航的标准方式是用
ShellRoute创建常驻的导航外壳,你的路由结构是独立的页面路由,不符合底部导航的场景需求。
修复步骤与代码示例
1. 修改路由配置,使用ShellRoute重构结构
将所有页面路由作为ShellRoute的子路由,让底部导航成为常驻的外壳组件:
import 'package:bops_app_v3/screens/add_screen.dart'; import 'package:bops_app_v3/screens/home_screen.dart'; import 'package:bops_app_v3/screens/product_screen.dart'; import 'package:bops_app_v3/screens/profile_screen.dart'; import 'package:bops_app_v3/widget/botton_navegation_widget.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; final router = GoRouter(routes: [ ShellRoute( builder: (context, state, child) { // 外壳组件:包含底部导航,子页面作为body内容 return Scaffold( body: child, bottomNavigationBar: const BottomNavigationWidget(), ); }, routes: [ GoRoute( path: '/', builder: (context, state) => const HomeScreen(), ), GoRoute( path: '/product', builder: (context, state) => const ProductScreen(), ), GoRoute( path: '/add', builder: (context, state) => const AddScreen(), ), GoRoute( path: '/profile', builder: (context, state) => const ProfileScreen(), ), ], ), ]);
2. 统一底部导航的导航方式并同步选中状态
修改BottomNavigationWidget,全部使用context.go,同时新增方法同步当前路由对应的选中索引:
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; class BottomNavigationWidget extends StatelessWidget { const BottomNavigationWidget({super.key}); @override Widget build(BuildContext context) { return BottomNavigationBar( selectedItemColor: Colors.blue, unselectedItemColor: Colors.black, currentIndex: _getCurrentIndex(context), onTap: (index) { switch (index) { case 0: context.go('/'); break; case 1: context.go('/product'); break; case 2: context.go('/add'); break; case 3: context.go('/profile'); break; } }, items: const [ BottomNavigationBarItem(icon: Icon(Icons.home_outlined), label: 'Home'), BottomNavigationBarItem( icon: Icon(Icons.production_quantity_limits_outlined), label: 'Product'), BottomNavigationBarItem(icon: Icon(Icons.add_outlined), label: 'Add'), BottomNavigationBarItem( icon: Icon(Icons.person_2_outlined), label: 'Profile'), ], ); } // 根据当前路由获取底部导航选中索引 int _getCurrentIndex(BuildContext context) { final location = GoRouterState.of(context).location; switch (location) { case '/': return 0; case '/product': return 1; case '/add': return 2; case '/profile': return 3; default: return 0; } } }
3. 修改页面组件,移除重复的底部导航
以HomeScreen为例,其他页面做同样修改:
import 'package:flutter/material.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State<HomeScreen> createState() => _HomeScreenState(); } class _HomeScreenState extends State<HomeScreen> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: const Text('Home screen'), // 移除重复的底部导航配置 ); } }
修复原理
ShellRoute创建了一个常驻的页面外壳,底部导航只会初始化一次,切换页面时仅替换child(即各个页面的body),符合底部导航的交互逻辑。- 统一使用
context.go确保导航上下文与当前页面绑定,避免了非调试模式下的路由实例上下文异常。 - 新增的
_getCurrentIndex方法让底部导航的选中状态与当前路由同步,提升用户体验。
内容的提问来源于stack exchange,提问作者cosmos multi
相关产品推荐
相关产品推荐

