Flutter go_router路由问题:ShellRoute底部导航高亮状态异常
GoRouter ShellRoute 底部导航高亮异常问题
路由结构
ShellRoute(routes: [ SettingsPage(routes: [/* 设置页子路由 */]), HomePage(routes: [ GoRoute(path: 'user-profile', builder: (context, state) => UserProfilePage()) ]), ])
场景说明
SettingsPage和HomePage作为ShellRoute的子路由,共享顶部AppBar与底部导航栏,点击底部导航项时对应图标会高亮。UserProfilePage是HomePage的子路由,使用独立导航器,不显示共享的AppBar和底部导航栏;按返回键会回到HomePage,可通过抽屉按钮进入该页面。
问题现象
当底部导航选中SettingsPage时,从抽屉打开UserProfilePage,返回后页面回到HomePage,但SettingsPage的底部导航图标仍保持高亮,与当前页面状态不匹配。
已尝试的方案(存在明显缺陷)
- 方案1:弃用
ShellRoute,给HomePage和SettingsPage各自添加底部导航栏。缺点是底部导航栏会出现跳动,且存在大量代码重复。 - 方案2:给
UserProfilePage传递来源页面数据,返回时根据数据跳转回对应页面。缺点是需要额外维护来源页面状态,逻辑冗余。
最优解决方案:路由状态驱动的底部导航高亮
核心思路
放弃手动维护底部导航的选中状态,直接通过GoRouter的当前路由路径来动态计算应该高亮的导航项。这样不管路由如何跳转,高亮状态始终和当前活跃的路由分支保持一致。
实现步骤
- 在底部导航组件中,通过
GoRouter.of(context).location获取当前路由的完整路径。 - 根据路径判断所属的路由分支:
- 若路径以
/settings开头,高亮设置页导航项; - 若路径以
/home开头(包括/home/user-profile这类子路由),高亮首页导航项;
- 若路径以
- 将判断逻辑封装为方法,绑定到底部导航的
currentIndex属性上。
示例代码
class BottomNavBar extends StatelessWidget { const BottomNavBar({super.key}); int _getActiveTabIndex(BuildContext context) { final currentPath = GoRouter.of(context).location; if (currentPath.startsWith('/settings')) { return 1; // 设置页对应的索引 } // 首页及其子路由都高亮首页 return 0; } @override Widget build(BuildContext context) { return BottomNavigationBar( currentIndex: _getActiveTabIndex(context), onTap: (index) { if (index == 0) { context.go('/home'); } else { context.go('/settings'); } }, items: const [ BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'), BottomNavigationBarItem(icon: Icons.settings, label: '设置'), ], ); } }
方案优势
- 彻底解决状态不一致问题:高亮状态完全由路由路径决定,无需手动同步。
- 保留
ShellRoute的优势:共享导航栏,无代码重复,也不会出现导航栏跳动问题。 - 逻辑简洁:不需要额外传递参数或维护状态,路由变化时自动同步高亮状态。
内容的提问来源于stack exchange,提问作者samadfullstack
相关产品推荐
相关产品推荐

