Flutter GoRouter+StatefulShellBranch返回键逻辑异常求助
解决GoRouter + StatefulShellBranch返回键异常问题
核心思路
通过PopScope接管全局返回逻辑,结合StatefulNavigationShell的分支状态判断,区分首页分支与其他分支的返回行为,同时避免分支切换时误触发退出提示。
具体实现步骤
1. 记录当前活跃分支索引
在底部导航组件中,通过回调实时更新当前分支索引,确保返回逻辑能准确判断当前所处分支:
class BottomNavPage extends StatelessWidget { final StatefulNavigationShell navigationShell; final ValueChanged<int> onBranchChanged; const BottomNavPage({ super.key, required this.navigationShell, required this.onBranchChanged, }); @override Widget build(BuildContext context) { return Scaffold( body: navigationShell, bottomNavigationBar: BottomNavigationBar( currentIndex: navigationShell.currentIndex, onTap: (index) { navigationShell.goBranch( index, initialLocation: index == navigationShell.currentIndex, ); // 更新当前分支索引 onBranchChanged(index); }, items: const [ BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"), BottomNavigationBarItem(icon: Icon(Icons.person), label: "个人中心"), // 另外两个分支的item ], ), ); } }
2. 用PopScope包裹全局路由,自定义返回逻辑
在StatefulShellRoute的builder中,通过PopScope拦截返回操作,根据当前分支和路由栈状态处理不同行为:
int _currentBranchIndex = 0; // 记录当前分支索引 final router = GoRouter( routes: [ StatefulShellRoute.indexedStack( builder: (context, state, navigationShell) { return PopScope( canPop: false, // 禁用默认返回行为 onPopInvoked: (didPop) async { if (didPop) return; // 先判断当前分支是否有子路由需要返回 final currentNavigator = navigationShell.navigator; if (currentNavigator != null && currentNavigator.canPop()) { currentNavigator.pop(); return; } // 无子女路由时,根据分支处理 if (_currentBranchIndex == 0) { // 首页分支:弹出退出确认弹窗 bool shouldExit = await showDialog( context: context, builder: (_) => AlertDialog( title: const Text("确认退出"), content: const Text("确定要退出应用吗?"), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text("取消"), ), TextButton( onPressed: () => Navigator.pop(context, true), child: const Text("确定"), ), ], ), ); if (shouldExit) SystemNavigator.pop(); } else { // 其他分支:切换至首页分支 navigationShell.goBranch(0); } }, child: BottomNavPage( navigationShell: navigationShell, onBranchChanged: (index) => _currentBranchIndex = index, ), ); }, branches: [ StatefulShellBranch( routes: [ GoRoute( path: "/", builder: (context, state) => const HomePage(), // 首页子路由 ), ], ), StatefulShellBranch( routes: [ GoRoute( path: "/profile", builder: (context, state) => const ProfilePage(), // 个人中心子路由 ), ], ), // 另外两个分支配置 ], ), ], );
关键说明
canPop: false:完全接管返回逻辑,避免默认的直接退出行为。- 子路由优先判断:确保在分支内有子页面时,先返回子页面,再处理分支级别的返回逻辑。
- 分支切换时更新索引:保证返回逻辑能准确识别当前所处分支,不会把分支切换误判为退出操作。
内容的提问来源于stack exchange,提问作者Priyanshu Singh
相关产品推荐
相关产品推荐

