Flutter GoRouter:ShellRoute二级路由跳转默认回到首个主页面问题
解决go_router中ShellRoute下二级路由跳转回到首页的问题
你的问题核心有两个:
- 所有二级路由只挂载在了Home主路由的子路由列表里,其他三个主路由(Search/Events/Account)下面没有这些二级路由的定义,所以跳转二级路由时,go_router只能匹配到Home下的对应路由,导致自动切回首页。
- 二级路由设置了
parentNavigatorKey: _rootNavigatorKey,这会让页面在根导航器中打开,完全脱离ShellRoute的结构,底部导航栏会被隐藏,同时路由栈也会重置。
步骤1:将二级路由分配到对应主路由下
如果某些二级路由是多个主路由共用的,可以封装成通用子路由列表,然后在每个主路由的routes里引入。修改GoRouter的ShellRoute部分:
ShellRoute( navigatorKey: _shellNavigatorKey, pageBuilder: (context, state, child) => MaterialPage( child: MainScreenWrapper(child: child), ), routes: [ // 循环生成所有主路由,每个主路由下都添加对应的子路由 ...mainScreens.map((mainScreen) { final List<RouteBase> childRoutes = []; // 添加通用二级路由 childRoutes.addAll(secondaryScreens.map((screen) => GoRoute( path: screen.path, name: screen.name, pageBuilder: (context, state) => MaterialPage( child: screen as Widget, ), ))); // 复用你之前的其他子路由配置 childRoutes.addAll(screensWithPathParams.map((screenEntity) => GoRoute( path: screenEntity.path, name: screenEntity.name, pageBuilder: (context, state) { final param = state.pathParameters[screenEntity.paramName]; return MaterialPage( child: screenEntity.build(context, param!), ); }, ))); childRoutes.addAll(screensWithParams.map((screenEntity) => GoRoute( path: screenEntity.path, name: screenEntity.name, pageBuilder: (context, state) { final extra = state.extra as ScreenProps; return MaterialPage( child: screenEntity.build(context, extra), ); }, ))); // 模态框/对话框类路由保留根导航器配置 childRoutes.addAll(modalEntities.map((modalEntity) => GoRoute( parentNavigatorKey: _rootNavigatorKey, path: modalEntity.path, name: modalEntity.name, pageBuilder: (context, state) => ModalPage( isDismissible: modalEntity.isDismissible, isScrollControlled: modalEntity.isScrollControlled, enableDrag: modalEntity.enableDrag, builder: (context) => modalEntity.build( context, state.extra as ModalProps, ref: ref, ), ), ))); // 继续添加其他类型路由... return GoRoute( parentNavigatorKey: _shellNavigatorKey, path: mainScreen.path, name: mainScreen.name, pageBuilder: (context, state) { return NoTransitionPage(child: mainScreen as Widget); }, routes: childRoutes, // 给每个主路由绑定子路由 ); }), ], ),
步骤2:调整跳转方式
跳转二级路由时,使用相对路径或者基于当前路由上下文的命名跳转,确保go_router在当前主路由的栈中加载子路由:
- 相对路径跳转(推荐,无需关心当前主路由):
// 从任意主路由跳转到ScreenUserSettings context.go('./${ScreenUserSettings().path}');
- 命名路由跳转(带父路由前缀):
// 获取当前主路由名称,作为父路由前缀 final currentMainRoute = GoRouterState.of(context).matchedLocation.split('/')[1]; context.goNamed( ScreenUserSettings().name, pathParameters: {}, parentNavigatorKey: _shellNavigatorKey, );
步骤3:修正二级路由的NavigatorKey
如果希望二级页面保留底部导航栏,移除二级路由的parentNavigatorKey: _rootNavigatorKey,这样会继承父路由的_shellNavigatorKey,页面在Shell的子导航栈中打开,底部导航栏保持可见。
如果是全屏模态框/对话框,保留parentNavigatorKey: _rootNavigatorKey,确保覆盖整个屏幕。
补充说明
- 之前只有Home主路由配置了子路由,其他主路由没有,所以跳二级路由时只能匹配到Home的子路由,导致切回首页。
context.go()会替换当前路由栈,context.push()会添加新页面到栈中,根据需求选择:需要返回主路由用push(),需要替换当前页面用go()。
内容的提问来源于stack exchange,提问作者Verilyzed
相关产品推荐
相关产品推荐

