Flutter升级后WillPopScope/PopScope在Android返回键无响应(go_router场景)
解决GoRouter + StatefulShellBranch下PopScope/WillPopScope无响应的问题
核心原因
GoRouter的StatefulShellBranch会接管页面的路由栈管理,直接在Dashboard的Scaffold外层套PopScope/WillPopScope,会被GoRouter的路由拦截逻辑覆盖,导致回调无法触发。
具体解决步骤
1. 正确放置PopScope的位置
需要将PopScope放在StatefulShellRoute的builder内部,而非Dashboard页面的外层。StatefulShellRoute作为底部导航的路由容器,只有在这里设置才能让GoRouter正确传递返回键事件。
示例代码:
StatefulShellRoute.indexedStack( builder: (context, state, navigationShell) { // 在此处包裹PopScope return PopScope( canPop: false, // 阻止默认返回行为 onPopInvoked: (bool didPop) async { if (!didPop) { // 实现双击返回退出逻辑 DateTime currentTime = DateTime.now(); static DateTime? _lastPressedTime; if (_lastPressedTime == null || currentTime.difference(_lastPressedTime!) > const Duration(seconds: 2)) { _lastPressedTime = currentTime; ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('再按一次退出应用')), ); } else { SystemNavigator.pop(); // 退出应用 } } }, child: DashboardPage(navigationShell: navigationShell), ); }, branches: [ StatefulShellBranch( routes: [ GoRoute( path: '/home', builder: (context, state) => const HomePage(), ), ], ), // 其他底部导航分支... ], )
2. 兼容子页面路由栈(可选)
如果子页面存在嵌套路由(比如Home页打开了详情页),需要在回调中先判断子页面路由栈是否可返回,再处理双击退出逻辑:
onPopInvoked: (bool didPop) async { if (!didPop) { final router = GoRouter.of(context); // 子页面路由栈有内容时,优先返回子页面 if (router.canPop()) { router.pop(); } else { // 触发双击退出逻辑 DateTime currentTime = DateTime.now(); static DateTime? _lastPressedTime; if (_lastPressedTime == null || currentTime.difference(_lastPressedTime!) > const Duration(seconds: 2)) { _lastPressedTime = currentTime; ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('再按一次退出应用')), ); } else { SystemNavigator.pop(); } } } }
3. 关键注意点
- 必须设置
canPop: false,避免GoRouter执行默认返回行为,确保回调逻辑生效。 - 不要在Dashboard页面内部嵌套PopScope/WillPopScope,否则会被外层路由容器拦截。
- 测试时需确保当前处于底部导航的根页面(无子页面栈),否则返回键会优先处理子页面路由。
内容的提问来源于stack exchange,提问作者james54
相关产品推荐
相关产品推荐

