Dialog
Flutter 提供多种弹窗:AlertDialog(确认弹窗)、SimpleDialog(选项弹窗)、BottomSheet(底部弹窗)、SnackBar(轻提示)。
构造函数
AlertDialog
dart
AlertDialog({
Key? key, // 组件标识
Widget? title, // 标题
EdgeInsetsGeometry? titlePadding, // 标题内边距
TextStyle? titleTextStyle, // 标题样式
Widget? content, // 内容
EdgeInsetsGeometry? contentPadding, // 内容内边距(默认 24)
TextStyle? contentTextStyle, // 内容样式
List<Widget>? actions, // 操作按钮列表(通常在底部)
EdgeInsetsGeometry? actionsPadding, // 按钮区域内边距
MainAxisAlignment? actionsAlignment, // 按钮对齐方式
bool scrollable = false, // 内容是否可滚动
Color? backgroundColor, // 背景色
double? elevation, // 阴影高度
Color? shadowColor, // 阴影颜色
ShapeBorder? shape, // 形状(圆角等)
String? semanticLabel, // 语义标签
AlignmentGeometry alignment, // 弹窗位置
})SimpleDialog
dart
SimpleDialog({
Key? key,
Widget? title, // 标题
EdgeInsetsGeometry? titlePadding, // 标题内边距
TextStyle? titleTextStyle, // 标题样式
List<Widget>? children, // 内容列表(常用 SimpleDialogOption)
EdgeInsetsGeometry? contentPadding, // 内容内边距
Color? backgroundColor,
double? elevation,
Color? shadowColor,
ShapeBorder? shape,
String? semanticLabel,
AlignmentGeometry alignment,
})SimpleDialogOption
dart
SimpleDialogOption({ // SimpleDialog 中的选项
Key? key,
VoidCallback? onPressed, // 点击回调
Widget? child, // 子组件
EdgeInsetsGeometry? padding, // 内边距(默认 16)
})BottomSheet
dart
// 持久化 BottomSheet(Scaffold.bottomSheet)
BottomSheet({
Key? key,
AnimationController? animationController, // 动画控制器
required WidgetBuilder builder, // 内容构建器(必填)
VoidCallback? onClosing, // 关闭回调
bool enableDrag = true, // 是否可拖拽关闭
Color? backgroundColor,
double? elevation,
ShapeBorder? shape,
})SnackBar
dart
SnackBar({
Key? key,
required Widget content, // 内容(必填)
Color? backgroundColor, // 背景色
double? elevation, // 阴影高度
EdgeInsetsGeometry? margin, // 外边距
EdgeInsetsGeometry? padding, // 内边距
double? width, // 宽度
ShapeBorder? shape, // 形状
SnackBarBehavior? behavior, // 显示行为
Duration duration = const Duration(milliseconds: 4000), // 显示时长
Animation<double>? animation, // 动画
VoidCallback? onVisible, // 显示回调
Widget? action, // 操作按钮(如 撤销)
VoidCallback? onActionPressed, // 操作按钮回调
})属性速查
AlertDialog 属性速查
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
title | Widget? | null | 标题 |
content | Widget? | null | 内容 |
actions | List<Widget>? | null | 底部操作按钮列表 |
scrollable | bool | false | 内容是否可滚动 |
backgroundColor | Color? | 主题 | 背景色 |
shape | ShapeBorder? | 圆角 | 形状 |
actionsAlignment | MainAxisAlignment? | end | 按钮对齐方式 |
alignment | AlignmentGeometry? | 居中 | 弹窗位置 |
SnackBar 属性速查
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
content | Widget | 必填 | 内容 |
backgroundColor | Color? | 主题 | 背景色 |
duration | Duration | 4 秒 | 显示时长 |
behavior | SnackBarBehavior? | fixed | 显示行为 |
action | SnackBarAction? | null | 操作按钮 |
margin | EdgeInsetsGeometry? | null | 外边距 |
shape | ShapeBorder? | null | 形状 |
SnackBarBehavior 速查
| 值 | 说明 |
|---|---|
SnackBarBehavior.fixed | 固定在底部,全宽 |
SnackBarBehavior.floating | 浮动在底部,有边距(M3 推荐) |
显示方式速查
| 方法 | 用途 | 返回值 |
|---|---|---|
showDialog() | 显示 Dialog | Future<T?> 关闭时的返回值 |
showModalBottomSheet() | 显示底部弹窗 | Future<T?> 关闭时的返回值 |
showMenu() | 显示菜单 | Future<T?> 选中的值 |
ScaffoldMessenger.of(context).showSnackBar() | 显示 SnackBar | 无 |
showDialog 参数
dart
showDialog({
required WidgetBuilder builder, // 弹窗构建器
BuildContext? context, // 上下文
bool barrierDismissible = true, // 点击外部是否关闭
Color? barrierColor, // 遮罩颜色
String? barrierLabel, // 遮罩语义标签
bool useSafeArea = true, // 是否避开安全区域
bool useRootNavigator = true, // 是否使用根导航器
RouteSettings? routeSettings, // 路由设置
Offset? anchorPoint, // 锚点位置
})showModalBottomSheet 参数
dart
showModalBottomSheet({
required WidgetBuilder builder,
BuildContext? context,
Color? backgroundColor,
double? elevation,
ShapeBorder? shape,
bool isScrollControlled = false, // 是否全屏高度
bool useSafeArea = false,
bool isDismissible = true, // 点击外部是否关闭
bool enableDrag = true, // 是否可拖拽关闭
double? closeProgressThreshold,
})快速示例
确认弹窗
dart
final result = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text('确认删除'),
content: Text('删除后无法恢复,确认删除吗?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false), // 返回 false
child: Text('取消'),
),
ElevatedButton(
onPressed: () => Navigator.pop(context, true), // 返回 true
child: Text('删除'),
),
],
),
);
if (result == true) {
// 确认删除
}选项弹窗
dart
final result = await showDialog<String>(
context: context,
builder: (context) => SimpleDialog(
title: Text('选择颜色'),
children: [
SimpleDialogOption(
onPressed: () => Navigator.pop(context, 'red'),
child: Text('红色'),
),
SimpleDialogOption(
onPressed: () => Navigator.pop(context, 'blue'),
child: Text('蓝色'),
),
SimpleDialogOption(
onPressed: () => Navigator.pop(context, 'green'),
child: Text('绿色'),
),
],
),
);底部弹窗
dart
final result = await showModalBottomSheet(
context: context,
isScrollControlled: true, // 允许全屏高度
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
builder: (context) => Padding(
padding: EdgeInsets.fromLTRB(16, 16, 16, MediaQuery.of(context).viewInsets.bottom),
child: Column(
mainAxisSize: MainAxisSize.min, // 必须,自适应高度
children: [
Text('选择操作', style: Theme.of(context).textTheme.titleLarge),
SizedBox(height: 16),
ListTile(leading: Icon(Icons.camera), title: Text('拍照'), onTap: () => Navigator.pop(context, 'camera')),
ListTile(leading: Icon(Icons.photo), title: Text('相册'), onTap: () => Navigator.pop(context, 'gallery')),
],
),
),
);SnackBar
dart
// 基本 SnackBar
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('保存成功')),
);
// 带操作按钮的 SnackBar
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('已删除'),
duration: Duration(seconds: 5),
action: SnackBarAction(
label: '撤销',
onPressed: () {
// 撤销删除
},
),
),
);
// 浮动样式 SnackBar
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('操作成功'),
behavior: SnackBarBehavior.floating, // 浮动样式
margin: EdgeInsets.fromLTRB(16, 0, 16, 16),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
);自定义 Dialog
dart
showDialog(
context: context,
builder: (context) => Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.check_circle, size: 64, color: Colors.green),
SizedBox(height: 16),
Text('操作成功', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
SizedBox(height: 8),
Text('您的数据已保存'),
SizedBox(height: 24),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () => Navigator.pop(context),
child: Text('确定'),
),
),
],
),
),
),
);加载弹窗
dart
showDialog(
context: context,
barrierDismissible: false, // 不可点击外部关闭
builder: (context) => Center(
child: Card(
child: Padding(
padding: EdgeInsets.all(24),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(),
SizedBox(width: 16),
Text('加载中...'),
],
),
),
),
),
);
// 关闭加载弹窗
Navigator.pop(context);常见错误
1. Dialog 中使用 context 错误
dart
// ❌ 错误:在 builder 中使用外层 context 关闭
showDialog(
builder: (context) => AlertDialog(
actions: [
TextButton(
onPressed: () => Navigator.pop(context), // 正确,使用 builder 的 context
),
],
),
);2. BottomSheet 内容被键盘遮挡
dart
// ✅ 修复:添加 viewInsets.bottom 内边距
showModalBottomSheet(
builder: (context) => Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom, // 避开键盘
),
child: TextField(...),
),
);3. 多个 SnackBar 排队显示
dart
// ❌ 错误:连续调用会排队显示
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('A')));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('B')));
// ✅ 修复:先清除再显示
ScaffoldMessenger.of(context).clearSnackBars();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('B')));