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:
- 在父Widget的State中定义GlobalKey:
final GlobalKey<NavigatorState> _navKey = GlobalKey<NavigatorState>();
- 将Key绑定到MaterialApp或Navigator:
MaterialApp( navigatorKey: _navKey, // ...其他配置 )
- 在弹窗按钮中使用该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
相关产品推荐
相关产品推荐

