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

使用auto_router时,showDialog中两次Navigator.pop致空白屏问题求助

问题解决:AutoRouter中从Dialog两次pop导致空白屏

问题原因

  1. 上下文不匹配:showDialog的context属于弹窗自身,第二次调用Navigator.pop(context)时,弹窗已经被关闭,该context已失效,会错误操作路由栈,破坏路由结构。
  2. 原生Navigator与AutoRouter冲突:使用AutoRouter管理路由,但调用原生Navigator.pop操作路由,两者的路由栈管理逻辑不一致,导致路由状态混乱。
  3. 栈空未处理退出逻辑:当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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 16:33:15