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

Flutter中WillPopScope结合showDialog不生效问题排查

问题描述

点击返回按钮时,预期弹出确认退出的AlertDialog,但点击后无弹窗显示,调试控制台仅输出pop in,未输出pop out。即使将WebView替换为简单Text组件,问题依然存在。

用户提供的代码:

class _MyAppState extends State<MyApp> {
  // This widget is the root of your application.
  WebViewController? _webViewController;
  final Completer<WebViewController> _completerController =
      Completer<WebViewController>();

  @override
  void initState() {
    super.initState();
    if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: WillPopScope(
        onWillPop: () async {
          print("pop in");
          final shouldPop = await showDialog<bool>(
            context: context,
            builder: (context) {
              return AlertDialog(
                title: const Text('Do you want to go back?'),
                actionsAlignment: MainAxisAlignment.spaceBetween,
                actions: [
                  TextButton(
                    onPressed: () {
                      Navigator.pop(context, true);
                    },
                    child: const Text('Yes'),
                  ),
                  TextButton(
                    onPressed: () {
                      Navigator.pop(context, false);
                    },
                    child: const Text('No'),
                  ),
                ],
              );
            },
          );
          print("pop out");
          return shouldPop!;
        },
        child: Scaffold(
          body: SafeArea(
            child: WebView(
              onWebViewCreated: (WebViewController webViewController) {
                _completerController.future
                    .then((value) => _webViewController = value);
                _completerController.complete(webViewController);
              },
              initialUrl: 'https://www.google.com',
              javascriptMode: JavascriptMode.unrestricted,
              zoomEnabled: false,
            ),
          ),
        ),
      ),
    );
  }
}
问题原因

核心问题是context层级错误:
MaterialApp内部会创建应用的根Navigator,而你在onWillPop中使用的context是_MyAppState的context,这个context属于MaterialApp的同级/父级,并未关联到MaterialApp内部的Navigator。导致showDialog无法找到正确的导航器来弹出对话框,代码卡在await showDialog步骤,因此不会执行到print("pop out")。

解决方案

以下两种方法任选其一即可:

方法一:使用Builder获取正确的context

通过Builder组件获取MaterialApp内部的context,再传入showDialog:

@override
Widget build(BuildContext context) {
  return MaterialApp(
    home: Builder(
      builder: (innerContext) {
        return WillPopScope(
          onWillPop: () async {
            print("pop in");
            final shouldPop = await showDialog<bool>(
              context: innerContext, // 使用Builder提供的内部context
              builder: (context) {
                return AlertDialog(
                  title: const Text('Do you want to go back?'),
                  actionsAlignment: MainAxisAlignment.spaceBetween,
                  actions: [
                    TextButton(
                      onPressed: () => Navigator.pop(context, true),
                      child: const Text('Yes'),
                    ),
                    TextButton(
                      onPressed: () => Navigator.pop(context, false),
                      child: const Text('No'),
                    ),
                  ],
                );
              },
            );
            print("pop out");
            return shouldPop ?? false; // 处理空值,默认不退出
          },
          child: Scaffold(
            body: SafeArea(
              child: WebView(
                onWebViewCreated: (WebViewController webViewController) {
                  _completerController.future
                      .then((value) => _webViewController = value);
                  _completerController.complete(webViewController);
                },
                initialUrl: 'https://www.google.com',
                javascriptMode: JavascriptMode.unrestricted,
                zoomEnabled: false,
              ),
            ),
          ),
        );
      },
    ),
  );
}

方法二:强制使用根Navigator弹窗

在showDialog中添加useRootNavigator: true参数,直接调用根导航器:

final shouldPop = await showDialog<bool>(
  context: context,
  useRootNavigator: true, // 强制使用根Navigator
  builder: (context) {
    return AlertDialog(
      title: const Text('Do you want to go back?'),
      actionsAlignment: MainAxisAlignment.spaceBetween,
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context, true),
          child: const Text('Yes'),
        ),
        TextButton(
          onPressed: () => Navigator.pop(context, false),
          child: const Text('No'),
        ),
      ],
    );
  },
);
return shouldPop ?? false; // 替换原有的shouldPop!,避免空指针
补充说明
  • 替换shouldPop!为shouldPop ?? false是为了处理用户点击弹窗外部关闭的情况(此时shouldPop为null),避免触发空指针异常。
  • 两种方案都能解决弹窗不显示的问题,根据代码结构选择即可。

内容的提问来源于stack exchange,提问作者Genie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 18:01:20