You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter路由切换后MaterialBanner无法关闭,报查询已停用组件祖先不安全错误

问题原因
  • 你先调用Navigator.of(context).pop()将RecoverScreen出栈后,RecoverScreen对应的context已经被标记为停用状态,后续无论是弹出Banner还是点击关闭按钮时,再通过这个已失效的context调用ScaffoldMessenger.of(context)查找祖先节点,就会触发报错。
  • MaterialBanner的关闭回调绑定的是RecoverScreen的失效上下文,点击时自然无法正常查找到ScaffoldMessenger实例执行隐藏操作。
解决方案

最优方案是提前持有上层全局的ScaffoldMessenger实例,避免依赖已销毁页面的context:

  1. 在执行页面pop操作前,先把当前context对应的ScaffoldMessenger实例保存下来
  2. 后续弹出Banner、隐藏Banner都直接使用这个提前保存的实例,不需要再通过context查找

修改后的核心代码如下:

// RecoverScreen中发送按钮的onPressed逻辑
onPressed: () {
  // 提前保存ScaffoldMessenger实例,避免后续使用失效的context
  final scaffoldMessenger = ScaffoldMessenger.of(context);
  // 执行页面返回操作
  Navigator.of(context).pop();
  // 用提前保存的实例弹出MaterialBanner
  scaffoldMessenger.showMaterialBanner(
    MaterialBanner(
      padding: const EdgeInsets.all(20),
      content: const Text('Recover password email was sended.'),
      leading: const Icon(Icons.info),
      backgroundColor: Colors.green,
      actions: <Widget>[
        TextButton(
          child: const Text(
            'Cerrar',
            style: TextStyle(color: Colors.white),
          ),
          onPressed: () {
            // 同样用提前保存的实例隐藏Banner
            scaffoldMessenger.hideCurrentMaterialBanner();
          },
        ),
      ],
    ),
  );
},
原理说明

Flutter中每个组件的context和其生命周期绑定,页面被pop销毁后,对应的context就不再可用,无法通过它查找祖先组件。提前保存ScaffoldMessenger的实例引用,绕开了后续对失效context的依赖,因此可以正常执行弹出和隐藏操作。

可选方案:如果业务逻辑允许,也可以通过路由传递回调函数的方式,让LoginScreen负责Banner的弹出和隐藏,所有操作都使用LoginScreen的有效上下文,也能避免该问题。

内容的提问来源于stack exchange,提问作者Alexis enp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 07:21:02