为StatefulShellRoute添加AnimatedSwitcher转场时出现重复GlobalKey错误
问题原因
StatefulNavigationShell内部自带全局唯一的GlobalKey,你直接用AnimatedSwitcher包裹它时,动画切换期间新旧两个SizedBox会同时持有同一个navigationShell实例,导致全局键重复冲突——Flutter不允许同一个全局键的widget同时存在于widget树的两个位置。
解决方案
放弃直接包裹navigationShell,改为让AnimatedSwitcher切换当前分支的页面实例,而非整个navigationShell。具体代码修改如下:
return StatefulShellRoute( builder: (context, state, navigationShell) { return Scaffold( body: AnimatedSwitcher( duration: const Duration(milliseconds: 500), switchInCurve: Curves.ease, switchOutCurve: Curves.ease, // 用当前索引作为唯一Key,确保AnimatedSwitcher识别页面变化 child: KeyedSubtree( key: ValueKey(navigationShell.currentIndex), child: navigationShell.currentBranch, ), ), bottomNavigationBar: BottomNavigationBar( currentIndex: navigationShell.currentIndex, onTap: (index) { navigationShell.goBranch( index, // 仅首次进入分支时跳转到初始路由,避免重复重建 initialLocation: index != navigationShell.currentIndex, ); }, items: const [ BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"), BottomNavigationBarItem(icon: Icon(Icons.settings), label: "设置"), ], ), ); }, branches: [ StatefulShellBranch( routes: [ GoRoute( path: "/", builder: (context, state) => const HomePage(), ), ], ), StatefulShellBranch( routes: [ GoRoute( path: "/settings", builder: (context, state) => const SettingsPage(), ), ], ), ], );
说明
- 这种方式保留了
StatefulShellRoute的状态管理能力(各分支页面状态会被缓存),同时实现了切换转场动画。 - 通过
ValueKey(navigationShell.currentIndex)确保AnimatedSwitcher能正确识别页面切换,避免全局键冲突——因为每次切换时处理的是不同分支的页面实例,而非同一个navigationShell。
内容的提问来源于stack exchange,提问作者Sayid
相关产品推荐
相关产品推荐

