Flutter响应式应用中如何动态设置parentNavigatorKey?
解决方案
问题核心在于GoRouter的路由配置是静态的,无法动态修改parentNavigatorKey,所以得换思路——根据屏幕尺寸选择导航器来触发跳转,而非依赖路由的静态配置。
步骤1:定义导航键
先声明两个导航键,分别对应根导航器和嵌套导航器(用于Shell布局):
final _rootNavigatorKey = GlobalKey<NavigatorState>(); final _shellNavigatorKey = GlobalKey<NavigatorState>();
步骤2:配置自适应Shell路由
用ShellRoute包裹标签页路由,根据屏幕宽度渲染侧边菜单或底部导航栏:
GoRouter router = GoRouter( navigatorKey: _rootNavigatorKey, initialLocation: '/', routes: [ ShellRoute( navigatorKey: _shellNavigatorKey, builder: (context, state, child) { final isDesktop = MediaQuery.of(context).size.width > 600; // 桌面端返回侧边菜单布局,移动端返回底部导航布局 return isDesktop ? SideMenuLayout(child: child) : BottomNavBarLayout(child: child); }, routes: [ // 首页等标签页路由 GoRoute( path: '/', builder: (context, state) => const HomePage(), ), // 其他标签页路由... ], ), // 详情页路由(独立于ShellRoute,不设置parentNavigatorKey) GoRoute( path: NotificationPage.path, builder: (context, state) => const NotificationPage(), ), ], );
步骤3:根据屏幕尺寸触发导航
在点击进入详情页的地方,判断当前设备类型,选择对应的导航器:
// 示例:点击通知图标跳转详情页 onTap: () { final isDesktop = MediaQuery.of(context).size.width > 600; if (isDesktop) { // 桌面端用嵌套导航器,侧边菜单保持显示 context.push(NotificationPage.path); } else { // 移动端用根导航器,覆盖底部导航栏 _rootNavigatorKey.currentState?.push(NotificationPage.path); } },
步骤4:处理直接访问详情页URL的情况
如果用户直接打开详情页的URL,通过redirect确保路由行为符合预期:
GoRouter router = GoRouter( navigatorKey: _rootNavigatorKey, initialLocation: '/', redirect: (context, state) { final isDesktop = MediaQuery.of(context).size.width > 600; // 桌面端访问详情页时,先进入Shell路由再加载详情页 if (isDesktop && state.location == NotificationPage.path) { return '/${NotificationPage.path}'; } return null; }, // 其他路由配置... );
为什么之前的动态设置无效?
GoRouter初始化后会固定路由配置,parentNavigatorKey作为路由的静态属性,无法在运行时动态修改。因此必须通过导航触发时选择导航器的方式,实现移动端和桌面端的不同导航行为。
内容的提问来源于stack exchange,提问作者Azamat Alimov
相关产品推荐
相关产品推荐

