本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、什么是 ScaffoldMessenger?

ScaffoldMessenger 是 Flutter 2.0 引入的一个新组件,用于管理 Scaffold 之间的消息传递(主要是 SnackBar)。它解决了旧版本中 Scaffold.of(context) 的一些问题,提供了更稳定、更灵活的 SnackBar 管理机制。

为什么要用 ScaffoldMessenger?

在 Flutter 2.0 之前,我们使用:

Scaffold.of(context).showSnackBar(snackBar);

这种方式存在的问题:

  • 上下文依赖:必须确保 context 在正确的 Scaffold 子树中

  • 路由切换问题:新页面覆盖时,SnackBar 可能不会消失

  • 生命周期问题:页面销毁时可能抛出异常

ScaffoldMessenger 不但解决了这些问题,还提供:

  • 全局管理:可以在任何地方显示 SnackBar

  • 路由感知:自动处理路由切换

  • 持久化:SnackBar 可以在页面切换时保持

  • 多消息队列:支持多个 SnackBar 排队显示

二、基本用法

2.1 获取 ScaffoldMessenger

方式1:使用 Builder 包装(推荐)
Scaffold(
  appBar: AppBar(title: Text('示例')),
  body: Builder(
    builder: (BuildContext context) {
      return Center(
        child: ElevatedButton(
          onPressed: () {
            // 在这里可以安全地使用 ScaffoldMessenger
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('你好!')),
            );
          },
          child: Text('显示 SnackBar'),
        ),
      );
    },
  ),
);
方式2:使用全局 context
class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('示例')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            // 使用 build 方法中的 context
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('你好!')),
            );
          },
          child: Text('显示 SnackBar'),
        ),
      ),
    );
  }
}
方式3:使用 ScaffoldMessenger 包裹
ScaffoldMessenger(
  child: Scaffold(
    appBar: AppBar(title: Text('示例')),
    body: Center(
      child: ElevatedButton(
        onPressed: () {
          // 从任何子 Widget 都可以访问
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('你好!')),
          );
        },
        child: Text('显示 SnackBar'),
      ),
    ),
  ),
);

2.2 显示简单的 SnackBar

// 基础用法
ScaffoldMessenger.of(context).showSnackBar(
  SnackBar(
    content: Text('操作成功!'),
    duration: Duration(seconds: 2), // 默认4秒
  ),
);

// 带动作按钮的 SnackBar
ScaffoldMessenger.of(context).showSnackBar(
  SnackBar(
    content: Text('文件已删除'),
    duration: Duration(seconds: 4),
    action: SnackBarAction(
      label: '撤销',
      onPressed: () {
        // 撤销操作
        ScaffoldMessenger.of(context).hideCurrentSnackBar();
      },
    ),
  ),
);

三、高级功能

3.1 自定义 SnackBar 样式

ScaffoldMessenger.of(context).showSnackBar(
  SnackBar(
    content: Row(
      children: [
        Icon(Icons.check_circle, color: Colors.white),
        SizedBox(width: 12),
        Expanded(
          child: Text(
            '操作成功完成!',
            style: TextStyle(fontSize: 16),
          ),
        ),
      ],
    ),
    backgroundColor: Colors.green,
    behavior: SnackBarBehavior.floating, // 浮动样式
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(10),
    ),
    elevation: 6,
    padding: EdgeInsets.symmetric(horizontal: 20, vertical: 16),
    margin: EdgeInsets.all(20), // 仅对 floating 有效
    duration: Duration(seconds: 3),
    action: SnackBarAction(
      label: '确定',
      textColor: Colors.yellow,
      onPressed: () {
        // 处理动作
      },
    ),
    onVisible: () {
      // SnackBar 显示时的回调
      print('SnackBar 已显示');
    },
    dismissDirection: DismissDirection.horizontal, // 滑动方向
    clipBehavior: Clip.hardEdge,
  ),
);

3.2 控制 SnackBar 显示

// 获取当前 ScaffoldMessengerState
final scaffoldMessengerState = ScaffoldMessenger.of(context);

// 1. 显示 SnackBar(返回可控制的 SnackBarController)
final controller = scaffoldMessengerState.showSnackBar(
  SnackBar(
    content: Text('处理中...'),
    duration: Duration(seconds: 10), // 设置较长时间
  ),
);

// 2. 关闭当前的 SnackBar
scaffoldMessengerState.hideCurrentSnackBar();

// 3. 关闭所有 SnackBar
scaffoldMessengerState.clearSnackBars();

// 4. 检查是否有 SnackBar 正在显示
if (scaffoldMessengerState.mounted) {
  // 可以通过其他方式判断,但没有直接的方法
}

// 5. 使用 SnackBarController 控制
Future.delayed(Duration(seconds: 3), () {
  controller.close(); // 手动关闭
  // 或者显示新内容
  // controller.closed.then((reason) {
  //   print('SnackBar 关闭原因: $reason');
  // });
});

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐