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

Flutter中Future.delay后showModalBottomSheet无法弹出问题求助

解决Flutter中关闭弹窗后延迟打开新弹窗的Null Check错误

错误原因

调用Navigator.pop(context)关闭第一个底部弹窗后,该弹窗对应的Widget会从Widget树中移除,其持有的context也不再处于活跃状态。延迟2秒后使用这个已失效的context调用showModalBottomSheet时,Flutter内部检查MediaQuery会访问已销毁Element的widget属性,该属性为null,从而触发「Null check operator used on a null value」错误。

解决方案

方法1:使用根导航Context

调用showModalBottomSheet时,改用根导航的context,确保即使当前弹窗的context失效,仍能正常打开新弹窗:

IconButton(
  onPressed: () {
    taskerFilterController.applyingLangaugePairChanges().whenComplete(() {
      Navigator.pop(context);
      // 获取根导航的context
      final rootContext = Navigator.of(context, rootNavigator: true);
      Future.delayed(const Duration(seconds: 2), () {
        if (mainLayoutController.contactType == 1 && mainLayoutController.locationName.isEmpty) {
          showModalBottomSheet(
            context: rootContext,
            builder: (BuildContext context) => const TaskType(),
            isScrollControlled: true,
          );
        }
      });
    });
  },
  icon: const Icon(Icons.done, size: 25, color: kGreen),
)

方法2:提前保存可用的Context

在父Widget中通过GlobalKey保存导航状态,后续使用该Key获取有效context:

  1. 在父Widget的State中定义GlobalKey:
final GlobalKey<NavigatorState> _navKey = GlobalKey<NavigatorState>();
  1. 将Key绑定到MaterialApp或Navigator:
MaterialApp(
  navigatorKey: _navKey,
  // ...其他配置
)
  1. 在弹窗按钮中使用该Key获取context:
IconButton(
  onPressed: () {
    taskerFilterController.applyingLangaugePairChanges().whenComplete(() {
      Navigator.pop(context);
      Future.delayed(const Duration(seconds: 2), () {
        if (mainLayoutController.contactType == 1 && mainLayoutController.locationName.isEmpty) {
          showModalBottomSheet(
            context: _navKey.currentContext!,
            builder: (BuildContext context) => const TaskType(),
            isScrollControlled: true,
          );
        }
      });
    });
  },
  icon: const Icon(Icons.done, size: 25, color: kGreen),
)

方法3:等待弹窗完全关闭后执行延迟操作

Navigator.pop会返回一个Future,等待它完成后再执行延迟,确保弹窗完全从路由栈移除:

IconButton(
  onPressed: () {
    taskerFilterController.applyingLangaugePairChanges().whenComplete(() async {
      // 等待弹窗完全关闭
      await Navigator.pop(context);
      Future.delayed(const Duration(seconds: 2), () {
        final rootContext = Navigator.of(context, rootNavigator: true);
        if (mainLayoutController.contactType == 1 && mainLayoutController.locationName.isEmpty) {
          showModalBottomSheet(
            context: rootContext,
            builder: (BuildContext context) => const TaskType(),
            isScrollControlled: true,
          );
        }
      });
    });
  },
  icon: const Icon(Icons.done, size: 25, color: kGreen),
)

关于是否可以不用Navigator.pop关闭showModalBottomSheet

官方的showModalBottomSheet是基于路由栈实现的,关闭它必须调用Navigator.pop(context)(或Navigator.of(context).pop())。如果想要不依赖Navigator控制弹窗显隐,需要自定义弹窗(比如在Stack中添加Widget,通过State变量控制显示状态),但这种方式不属于官方showModalBottomSheet的范畴。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 05:45:32