You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter嵌套Navigator用GlobalKey跨兄弟组件导航报重复Key错误求替代方案

错误原因

你报错的核心原因是 RightSideNavigator 里的 navigationKey 是静态全局唯一的,但你在 PageOne 和 PageTwo 中都实例化了 RightSideNavigator 组件。当你从 PageOne 跳转到 PageTwo 时,PageOne 还保存在路由栈中没有被销毁,此时 widget 树中同时存在两个持有同一个 GlobalKey 的 Navigator 组件,就触发了重复 GlobalKey 的报错。

可行替代方案

方案1:调整布局结构,全局唯一侧边导航(最推荐)

不要在每个业务页面(PageOne/PageTwo)中单独嵌入侧边导航,把侧边导航提到根层级,和主内容区的路由平级,全局只保留一个 RightSideNavigator 实例,从根源上避免重复 GlobalKey 的问题,也符合你全局控制侧边路由的需求。

修改后的 MyApp 代码示例:

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Right Slider Navigation Demo',
      theme: ThemeData(
        primarySwatch: Colors.blueGrey,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Scaffold(
        body: Row(
          children: [
            // 左侧主内容区,单独用一个Navigator托管业务页面路由
            Expanded(
              child: Navigator(
                initialRoute: "/page1",
                onGenerateRoute: (settings) {
                  Widget page;
                  switch(settings.name) {
                    case "/page1":
                      page = const PageOne();
                      break;
                    case "/page2":
                      page = const PageTwo();
                      break;
                    default:
                      page = const PageOne();
                  }
                  return MaterialPageRoute(builder: (_) => page);
                },
              ),
            ),
            // 右侧全局唯一的侧边导航,不会随主内容路由切换重建
            Container(
              decoration: BoxDecoration(border: Border.all(color: Colors.blueGrey)),
              child: ConstrainedBox(
                constraints: BoxConstraints.tightFor(width: MediaQuery.of(context).size.width * 0.3),
                child: RightSideNavigator(
                  initialRoute: "/",
                  routes: {
                    '/': (context) => const RightSideNavigationView(),
                    '/menu_one': (context) => const MenuOne(),
                  },
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

对应修改业务页面的跳转逻辑:PageOne/PageTwo 去掉内嵌的侧边导航代码,跳转到PageTwo改用 Navigator.of(context).pushNamed("/page2") 即可,原有的 RightSideNavigator.navigator().push 逻辑完全不用改。


方案2:用事件通信替代全局GlobalKey

如果你必须保留每个页面单独嵌入侧边导航的结构,可以用状态管理的事件分发机制来触发路由跳转,完全不需要全局Key:

  1. 定义一个全局的事件控制器,比如用Flutter自带的StreamController:
// 全局事件单例
final sideNavEvent = StreamController<RouteSettings>.broadcast();
  1. 把RightSideNavigator改为StatefulWidget,在初始化时监听事件,收到事件后调用当前组件内的Navigator.of(context)执行跳转:
@override
void initState() {
  super.initState();
  _subscription = sideNavEvent.stream.listen((routeSettings) {
    if (mounted) {
      Navigator.of(context).pushNamed(routeSettings.name, arguments: routeSettings.arguments);
    }
  });
}

@override
void dispose() {
  _subscription.cancel();
  super.dispose();
}
  1. 所有需要触发侧边导航跳转的位置,改为发送事件即可:
// 原来的RightSideNavigator.navigator().pushNamed("/menu_one") 改为
sideNavEvent.add(const RouteSettings(name: "/menu_one"));

内容的提问来源于stack exchange,提问作者Sanket

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 17:09:01