Flutter中QuickAlert弹窗内Navigator导航失败问题求助
解决Flutter中QuickAlert确认按钮导航时的
!_debugLocked断言错误 问题场景
在MaterialApp深层的ItemDetailsScreen页面中,调用BLE控制器的onBleStatusChange方法弹出QuickAlert弹窗,点击确认按钮尝试导航到MyNextScreen时,触发以下断言错误:
======== Exception caught by scheduler library ===================================================== The following assertion was thrown during a scheduler callback: 'package:flutter/src/widgets/navigator.dart': Failed assertion: line 4475 pos 12: '!_debugLocked': is not true. ...(省略栈信息)
尝试过添加Future.delayed(Duration.zero)、抽离导航函数、传递BuildContext或使用GetX的Get.to()导航,均未解决问题。
相关代码片段:
class ItemDetailsScreen extends StatefulWidget { ItemDetailsScreen(); @override State<ItemDetailsScreen> createState() => _ItemDetailsScreenState(); } class _ItemDetailsScreenState extends State<ItemDetailsScreen> { @override Widget build(BuildContext context) { // 注意:此处直接在build中调用可能导致重复弹窗 bleController.onBleStatusChange('box_is_open', context); return Scaffold(....); } } Future<void> onBleStatusChange() async { // ...其他逻辑 QuickAlert.show( context: context, type: QuickAlertType.success, title: 'Box geöffnet!', text: 'Bitte entnimm jetzt das Item', confirmBtnText: 'Weiter', onConfirmBtnTap: () { Navigator.of(context).push( MaterialPageRoute( builder: (context) => const MyNextScreen())); // 触发错误 } ); }
问题原因
这个错误的核心是:在Flutter框架的绘制锁定阶段(比如弹窗关闭的动画过程中)尝试执行导航操作。QuickAlert的确认按钮默认会先触发弹窗关闭的动画,此时Navigator处于锁定状态(_debugLocked为true),直接调用push会违反断言约束。
解决方案
方案1:确保弹窗完全关闭后再执行导航
手动关闭弹窗后,通过WidgetsBinding.addPostFrameCallback或Future.microtask延迟导航,确保弹窗关闭的动画完成、Navigator解锁后再执行操作:
QuickAlert.show( context: context, type: QuickAlertType.success, title: 'Box geöffnet!', text: 'Bitte entnimm jetzt das Item', confirmBtnText: 'Weiter', onConfirmBtnTap: () { // 先关闭当前QuickAlert弹窗 Navigator.pop(context); // 在当前帧绘制完成后执行导航 WidgetsBinding.instance.addPostFrameCallback((_) { Navigator.of(context).push( MaterialPageRoute(builder: (_) => const MyNextScreen()) ); }); } );
或者使用Future.microtask:
onConfirmBtnTap: () { Navigator.pop(context); Future.microtask(() { Navigator.of(context).push( MaterialPageRoute(builder: (_) => const MyNextScreen()) ); }); }
方案2:使用GetX导航的适配写法
如果项目用GetX,同样需要等待弹窗关闭后再调用导航:
onConfirmBtnTap: () { Navigator.pop(context); // 关闭QuickAlert Future.microtask(() { Get.to(() => const MyNextScreen()); }); }
额外优化:避免在build中重复触发弹窗
原代码中直接在build方法调用bleController.onBleStatusChange,会导致页面重建时重复弹窗,建议将该调用移到initState中:
@override void initState() { super.initState(); // 延迟到第一帧绘制完成后调用,避免context未就绪问题 WidgetsBinding.instance.addPostFrameCallback((_) { bleController.onBleStatusChange('box_is_open', context); }); } @override Widget build(BuildContext context) { return Scaffold(....); }
内容的提问来源于stack exchange,提问作者Boommeister
相关产品推荐
相关产品推荐

