Flutter中关闭showModalBottomSheet后点击Snackbar操作触发‘Looking up a deactivated widget's ancestor is unsafe’错误的解决方案咨询
问题分析与解决方案
你遇到的这个错误核心原因很明确:SnackBar的操作按钮使用了已经被销毁的Widget上下文。
当你在CreateFavouriteSuccess分支里先调用ScaffoldMessenger.of(context).showSnackBar(),紧接着执行Navigator.of(context).pop()关闭底部弹窗时,BlocListener所在的整个弹窗Widget会被标记为deactivated(销毁状态)。而SnackBar的SnackBarAction里的context,正是这个已经失效的弹窗Widget的上下文。当你点击操作按钮时,用这个失效的上下文去查找ScaffoldMessenger,就触发了"Looking up a deactivated widget's ancestor"的错误。
下面给你几个简单有效的解决办法:
方案1:提前保存ScaffoldMessenger实例(代码改动最小)
在弹窗Widget还未被销毁时,先获取有效的ScaffoldMessenger实例并保存,后续操作直接调用这个实例,彻底避开对失效上下文的依赖:
else if (state is CreateFavouriteSuccess) { // 提前拿到有效的ScaffoldMessenger对象 final messenger = ScaffoldMessenger.of(context); messenger.showSnackBar( SnackBar( content: AutoSizeText(state.successMessage), duration: const Duration(seconds: 3), action: SnackBarAction( label: kYes, onPressed: () { // 直接用提前保存的messenger实例操作 messenger.hideCurrentSnackBar(); }, ), ), ); Navigator.of(context).pop(); }
方案2:使用全局GlobalKey绑定ScaffoldMessenger
如果你的弹窗是在某个父页面中弹出的,可以通过全局Key直接获取父页面的ScaffoldMessenger,完全脱离弹窗上下文的限制:
- 在父页面定义全局Key:
final GlobalKey<ScaffoldMessengerState> _messengerKey = GlobalKey<ScaffoldMessengerState>();
- 把Key绑定到父页面的Scaffold:
Scaffold( key: _messengerKey, // 其他页面内容... )
- 在弹窗的BlocListener中使用这个全局Key:
else if (state is CreateFavouriteSuccess) { _messengerKey.currentState?.showSnackBar( SnackBar( content: AutoSizeText(state.successMessage), duration: const Duration(seconds: 3), action: SnackBarAction( label: kYes, onPressed: () { _messengerKey.currentState?.hideCurrentSnackBar(); }, ), ), ); Navigator.of(context).pop(); }
方案3:将SnackBar移到父页面显示
如果你的Bloc是在父页面中提供的,可以调整逻辑,等弹窗关闭后再在父页面显示SnackBar:
// 父页面调用弹窗的代码 await showModalBottomSheet( context: context, builder: (context) => YourFavouriteFormWidget(), ); // 弹窗关闭后,在这里显示成功提示 ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: AutoSizeText("文件添加成功")), );
这种方法需要你调整状态触发逻辑,比如在弹窗中完成操作后,通过Bloc状态通知父页面显示SnackBar。
内容的提问来源于stack exchange,提问作者Alex Aung
相关产品推荐
相关产品推荐

