Flutter定时器结束触发弹窗报错求助:setState调用时机问题
解决Flutter中定时器归零触发弹窗报错的问题
我明白你遇到的困扰了!你在AnimatedBuilder的构建过程中调用showDialog时出现了setState() or markNeedsBuild() called during build错误,但同样的弹窗在GestureDetector的点击回调里却能正常运行,这是因为两者的执行时机完全不同:
GestureDetector的onTap是用户交互触发的回调,它发生在Flutter的构建周期之外,所以调用showDialog不会干扰当前的Widget构建流程。- 而
AnimatedBuilder的builder方法是在Widget构建过程中执行的,此时Flutter正处于更新UI的阶段,不允许触发任何会修改Widget树状态的操作(比如弹窗,因为弹窗会触发新的UI构建),这就导致了报错。
下面给你两个可行的解决方案:
方案一:使用WidgetsBinding延迟执行弹窗
通过WidgetsBinding.instance.addPostFrameCallback,可以让弹窗在当前Widget构建完成后再执行,这样就不会干扰构建流程了。修改你的autoSubmition函数如下:
void autoSubmition() { // 等待当前build周期结束后再触发弹窗 WidgetsBinding.instance.addPostFrameCallback((_) { var autoResponse = { "submitDialogTitle": "Your have ran out of time. Please Submit you answer", "submitDialogSubtitle": "If you cancel this test will be terminated. Your score will be reset to zero" }; showDialog( context: context, barrierDismissible: false, builder: (_) { return AutoSubmitTestDialog( context: context, model: model, testItem: testItem, messages: autoResponse); }, ); }); }
方案二:监听AnimationController的状态变化(更推荐)
比起在AnimatedBuilder里每次构建都判断controller.value,直接监听动画控制器的状态变化会更高效、更符合Flutter的设计逻辑。比如你的控制器是从某个值递减到0,当动画完成时触发弹窗:
在你的Widget的initState方法中添加状态监听:
@override void initState() { super.initState(); // 监听动画状态变化 controller.addStatusListener((status) { // 当动画完成且值为0时触发弹窗 if (status == AnimationStatus.completed && controller.value == 0) { autoSubmition(); // 记得如果不需要再次监听,可以在这里移除listener避免内存泄漏 // controller.removeStatusListener(this); } }); }
这样当动画自然结束到0时,就会自动触发弹窗,而且完全不会干扰Widget的构建流程。
这两种方法都能解决你的问题,其中方案二更推荐,因为它的逻辑更清晰,也避免了在builder方法中做额外的判断操作。
内容的提问来源于stack exchange,提问作者MEHEDI HASAN
相关产品推荐
相关产品推荐

