Flutter中第二次点击PopupMenuButton菜单项触发navigator断言失败求助
嘿,我来帮你搞定这个头疼的问题!你遇到的这个'package:flutter/src/widgets/navigator.dart': Failed assertion: line 1846 pos 12: '!_debugLocked': is not true异常,是Flutter导航框架里的典型场景问题——在导航状态被锁定时尝试发起新的导航操作,而PopupMenuButton的点击回调刚好容易踩这个坑。
问题原因
当你点击PopupMenu的菜单项时,框架会自动触发弹窗关闭的逻辑,这个过程中会临时锁定导航状态(把_debugLocked设为true)。如果你的onSelected回调里直接调用Navigator.push这类导航方法,第一次点击可能刚好“卡”在锁定前执行成功,但第二次点击时,弹窗关闭的锁定逻辑和你的导航操作撞在了一起,就触发了这个断言错误。
解决方案
核心思路就是延迟导航操作,等弹窗完全关闭、导航状态解锁后再执行,这里给你两种靠谱的实现方式:
方式1:使用addPostFrameCallback(推荐)
这个方法会在当前Widget树的构建、布局、绘制全部完成后再执行回调,完美避开弹窗关闭的锁定周期:
onSelected: (PopupMenuChoice choice) { WidgetsBinding.instance.addPostFrameCallback((_) { Navigator.push(context, choice.pageRoute); }); },
方式2:使用Future.delayed(Duration.zero)
这也是一种延迟执行的方式,效果和上面类似,本质是把导航操作放到下一个事件循环里:
onSelected: (PopupMenuChoice choice) { Future.delayed(Duration.zero, () { Navigator.push(context, choice.pageRoute); }); },
完整代码示例
结合你定义的PopupMenuChoice类,完整的使用示例如下:
class PopupMenuChoice { const PopupMenuChoice({this.title, this.pageRoute}); final String title; final MaterialPageRoute pageRoute; } // 在你的Widget构建方法里使用PopupMenuButton PopupMenuButton<PopupMenuChoice>( itemBuilder: (BuildContext context) => <PopupMenuEntry<PopupMenuChoice>>[ PopupMenuItem<PopupMenuChoice>( value: PopupMenuChoice( title: "我的页面", pageRoute: MaterialPageRoute(builder: (_) => const MyTargetPage()), ), child: const Text("我的页面"), ), // 可以添加更多菜单项 ], onSelected: (PopupMenuChoice choice) { // 用推荐的方式延迟导航 WidgetsBinding.instance.addPostFrameCallback((_) { Navigator.push(context, choice.pageRoute); }); }, )
额外提醒
作为Flutter新手,要多留意框架的状态更新时机——很多这类断言错误,都是因为在框架正在处理状态变更(比如弹窗关闭、组件重建)的时候,发起了新的状态或导航操作,延迟执行是解决这类问题的常用技巧哦。
内容的提问来源于stack exchange,提问作者maeni70
相关产品推荐
相关产品推荐

