Flutter中 ScaffoldMessenger 消息通知
Flutter 2.0引入的ScaffoldMessenger组件优化了SnackBar的管理机制,解决了旧版本中上下文依赖、路由切换和生命周期等问题。它支持全局管理SnackBar,自动处理路由切换,并能保持消息持久化。使用方式包括Builder包装、全局context和ScaffoldMessenger包裹三种方法。除了基础用法外,还支持自定义样式(如浮动效果、圆角、图标等)和高级控制(手动关
·
本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、什么是 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');
// });
});
更多推荐

所有评论(0)