使用auto_router时,showDialog中两次Navigator.pop致空白屏问题求助
问题解决:AutoRouter中从Dialog两次pop导致空白屏
问题原因
- 上下文不匹配:
showDialog的context属于弹窗自身,第二次调用Navigator.pop(context)时,弹窗已经被关闭,该context已失效,会错误操作路由栈,破坏路由结构。 - 原生Navigator与AutoRouter冲突:使用AutoRouter管理路由,但调用原生
Navigator.pop操作路由,两者的路由栈管理逻辑不一致,导致路由状态混乱。 - 栈空未处理退出逻辑:当AutoRouter的路由栈为空时,持续执行
pop不会触发应用退出,只会显示空白屏。
解决方案
1. 用AutoRouter的pop方法操作路由
直接通过AutoRouter.of(context)获取路由实例,调用其pop方法,确保操作的是AutoRouter的路由栈:
TextButton( child: const Text('Leave'), onPressed: () { // 先关闭弹窗 Navigator.pop(context); // 调用AutoRouter的pop返回上一页 AutoRouter.of(context).pop(); }, )
2. 区分弹窗上下文与页面上下文
提前保存页面的context,弹窗关闭后用页面context执行页面的pop操作,避免使用已失效的弹窗上下文:
// 在页面State类中初始化页面上下文 final _pageContext = context; void _showBackDialog() { showDialog<void>( context: _pageContext, builder: (BuildContext dialogContext) { // 用dialogContext标记弹窗上下文 return AlertDialog( alignment: Alignment.bottomCenter, title: const Text('Are you sure?'), content: const Text('Are you sure you want to leave this page?'), actions: <Widget>[ TextButton( child: const Text('Nevermind'), onPressed: () => Navigator.pop(dialogContext), ), TextButton( child: const Text('Leave'), onPressed: () { // 关闭弹窗用弹窗上下文 Navigator.pop(dialogContext); // 页面pop用页面上下文 Navigator.pop(_pageContext); }, ), ], ); }, ); }
3. 处理路由栈为空的退出逻辑
在pop前检查AutoRouter的栈长度,为空时直接调用系统方法退出应用:
TextButton( child: const Text('Leave'), onPressed: () { Navigator.pop(context); final router = AutoRouter.of(context); if (router.stack.length <= 1) { // 路由栈为空,退出应用 SystemNavigator.pop(); } else { router.pop(); } }, )
4. 优化PopScope逻辑
简化onPopInvoked的处理逻辑,避免不必要的日志和重复判断:
PopScope( canPop: false, onPopInvoked: (didPop) { if (didPop) return; _showBackDialog(); }, child: // 页面主体内容 )
修改后的完整示例
class YourPage extends StatefulWidget { const YourPage({super.key}); @override State<YourPage> createState() => _YourPageState(); } class _YourPageState extends State<YourPage> { late final BuildContext _pageContext; @override void initState() { super.initState(); _pageContext = context; } @override Widget build(BuildContext context) { return PopScope( canPop: false, onPopInvoked: (didPop) { if (didPop) return; _showBackDialog(); }, child: Scaffold( // 页面主体内容 ), ); } void _showBackDialog() { showDialog<void>( context: _pageContext, builder: (BuildContext dialogContext) { return AlertDialog( alignment: Alignment.bottomCenter, title: const Text('Are you sure?'), content: const Text('Are you sure you want to leave this page?'), actions: <Widget>[ TextButton( style: TextButton.styleFrom( textStyle: Theme.of(context).textTheme.labelLarge, ), child: const Text('Nevermind'), onPressed: () => Navigator.pop(dialogContext), ), TextButton( style: TextButton.styleFrom( textStyle: Theme.of(context).textTheme.labelLarge, ), child: const Text('Leave'), onPressed: () { Navigator.pop(dialogContext); final router = AutoRouter.of(_pageContext); if (router.stack.length <= 1) { SystemNavigator.pop(); } else { router.pop(); } }, ), ], ); }, ); } }
内容的提问来源于stack exchange,提问作者Anjar Naufal
相关产品推荐
相关产品推荐

