Skip to content

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 属性速查

属性类型默认值说明
titleWidget?null标题
contentWidget?null内容
actionsList<Widget>?null底部操作按钮列表
scrollableboolfalse内容是否可滚动
backgroundColorColor?主题背景色
shapeShapeBorder?圆角形状
actionsAlignmentMainAxisAlignment?end按钮对齐方式
alignmentAlignmentGeometry?居中弹窗位置

SnackBar 属性速查

属性类型默认值说明
contentWidget必填内容
backgroundColorColor?主题背景色
durationDuration4 秒显示时长
behaviorSnackBarBehavior?fixed显示行为
actionSnackBarAction?null操作按钮
marginEdgeInsetsGeometry?null外边距
shapeShapeBorder?null形状

SnackBarBehavior 速查

说明
SnackBarBehavior.fixed固定在底部,全宽
SnackBarBehavior.floating浮动在底部,有边距(M3 推荐)

显示方式速查

方法用途返回值
showDialog()显示 DialogFuture<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')));

基于 Flutter 官方文档整理