对话框组件详解

对话框是与用户交互的重要方式,用于显示重要信息、确认操作或收集输入。Flutter 提供了多种对话框组件。本教程将详细介绍各种对话框。

重要提示:Flutter 3.28+ 增强了对话框的样式和动画效果,提供更好的用户体验。

1. AlertDialog 警告对话框

AlertDialog 是最常用的对话框,用于显示警告、确认信息。

📐 AlertDialog 渲染效果

标题
这是对话框的内容区域,用于显示提示信息。
取消
确定
// 基本对话框
showDialog(
  context: context,
  builder: (context) => AlertDialog(
    title: const Text('确认删除'),
    content: const Text('确定要删除这个项目吗?'),
    actions: [
      TextButton(
        onPressed: () => Navigator.pop(context),
        child: const Text('取消'),
      ),
      TextButton(
        onPressed: () {
          Navigator.pop(context);
          // 执行删除操作
        },
        child: const Text('删除'),
      ),
    ],
  ),
);

// 带图标的对话框
showDialog(
  context: context,
  builder: (context) => AlertDialog(
    icon: const Icon(Icons.warning, color: Colors.orange),
    title: const Text('警告'),
    content: const Text('此操作不可撤销!'),
    actions: [
      TextButton(
        onPressed: () => Navigator.pop(context),
        child: const Text('知道了'),
      ),
    ],
  ),
);

2. SimpleDialog 简单对话框

SimpleDialog 用于提供选项列表供用户选择。

📐 SimpleDialog 渲染效果

选择操作
👁️ 查看详情
✏️ 编辑
🗑️ 删除
showDialog(
  context: context,
  builder: (context) => SimpleDialog(
    title: const Text('选择操作'),
    children: [
      SimpleDialogOption(
        onPressed: () {
          Navigator.pop(context, '查看');
        },
        child: const Text('查看详情'),
      ),
      SimpleDialogOption(
        onPressed: () {
          Navigator.pop(context, '编辑');
        },
        child: const Text('编辑'),
      ),
      SimpleDialogOption(
        onPressed: () {
          Navigator.pop(context, '删除');
        },
        child: const Text('删除'),
      ),
    ],
  ),
).then((value) {
  if (value != null) {
    print('选择了: $value');
  }
});

3. BottomSheet 底部表单

BottomSheet 从屏幕底部滑出,适合显示更多内容。

📐 BottomSheet 渲染效果

页面内容区域
底部表单内容
选项1
选项2
// 模态底部表单
showModalBottomSheet(
  context: context,
  isScrollControlled: true,
  builder: (context) => Container(
    padding: const EdgeInsets.all(20),
    height: 300,
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        const Text(
          '选择日期',
          style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
        ),
        const SizedBox(height: 20),
        const TextField(
          decoration: InputDecoration(
            labelText: '日期',
            hintText: '请选择日期',
            border: OutlineInputBorder(),
          ),
        ),
        const SizedBox(height: 20),
        ElevatedButton(
          onPressed: () => Navigator.pop(context),
          child: const Text('确定'),
        ),
      ],
    ),
  ),
);

// 持久底部表单
Scaffold(
  body: const Center(child: Text('内容')),
  bottomSheet: Container(
    height: 100,
    color: Colors.blue,
    child: const Center(
      child: Text('底部表单', style: TextStyle(color: Colors.white)),
    ),
  ),
);

4. SnackBar 轻量提示

SnackBar 用于显示简短的消息提示。

📐 SnackBar 渲染效果

页面内容区域
操作成功 撤销

从底部弹出,短暂显示后自动消失

// 基本提示
ScaffoldMessenger.of(context).showSnackBar(
  const SnackBar(content: Text('操作成功')),
);

// 带动作的提示
ScaffoldMessenger.of(context).showSnackBar(
  SnackBar(
    content: const Text('已删除'),
    action: SnackBarAction(
      label: '撤销',
      onPressed: () {
        // 撤销操作
      },
    ),
  ),
);

// 带图标的提示
final snackBar = SnackBar(
  content: const Row(
    children: [
      Icon(Icons.check_circle, color: Colors.white),
      SizedBox(width: 8),
      Text('保存成功'),
    ],
  ),
  backgroundColor: Colors.green,
  duration: const Duration(seconds: 2),
);

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

5. showDialog 显示对话框

showDialog 是显示对话框的核心方法。

📐 showDialog 返回值流程

1. 显示对话框

页面内容
确认
确定要继续吗?

2. 用户选择

取消
确定

3. 返回结果

true/false

showDialog 返回 Future,可以获取用户选择的值

// 带返回值的对话框
Future showConfirmDialog(BuildContext context) {
  return showDialog(
    context: context,
    builder: (context) => AlertDialog(
      title: const Text('确认'),
      content: const Text('确定要继续吗?'),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context, false),
          child: const Text('取消'),
        ),
        TextButton(
          onPressed: () => Navigator.pop(context, true),
          child: const Text('确定'),
        ),
      ],
    ),
  );
}

// 使用
final confirmed = await showConfirmDialog(context);
if (confirmed == true) {
  print('用户确认了');
}

6. showDialog 全局对话框

使用 navigatorKey 显示全局对话框。

📐 全局对话框工作原理

MaterialApp

App
navigatorKey

任意位置调用

showDialog()

显示对话框

全局对话框
无需 context

通过 GlobalKey 在应用任何位置显示对话框,不受页面层级限制

// 在 MaterialApp 中设置 navigatorKey
final GlobalKey navigatorKey = GlobalKey();

MaterialApp(
  navigatorKey: navigatorKey,
  home: const HomePage(),
);

// 在任何地方显示对话框
void showGlobalDialog() {
  showDialog(
    context: navigatorKey.currentContext!,
    builder: (context) => AlertDialog(
      title: const Text('全局对话框'),
      content: const Text('这是一个全局对话框'),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: const Text('关闭'),
        ),
      ],
    ),
  );
}

7. DatePickerDialog 日期选择器

日期选择器用于选择日期。

📐 DatePickerDialog 渲染效果

2024年3月
25
26
27
28
29
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
取消
确定

日历视图,支持选择年月日

// 显示日期选择器
Future _selectDate() async {
  final DateTime? picked = await showDatePicker(
    context: context,
    initialDate: DateTime.now(),
    firstDate: DateTime(2020),
    lastDate: DateTime(2030),
    helpText: '选择日期',
    cancelText: '取消',
    confirmText: '确定',
    locale: const Locale('zh', 'CN'),
  );

  if (picked != null) {
    setState(() {
      _selectedDate = picked;
    });
  }
}

// 显示日期范围选择器
Future _selectDateRange() async {
  final DateTimeRange? picked = await showDateRangePicker(
    context: context,
    firstDate: DateTime(2020),
    lastDate: DateTime(2030),
    helpText: '选择日期范围',
    cancelText: '取消',
    confirmText: '确定',
    saveText: '保存',
  );

  if (picked != null) {
    setState(() {
      _dateRange = picked;
    });
  }
}

8. TimePickerDialog 时间选择器

时间选择器用于选择时间。

📐 TimePickerDialog 渲染效果

选择时间
14
小时
:
30
分钟
取消
确定

24小时制,分别选择小时和分钟

// 显示时间选择器
Future _selectTime() async {
  final TimeOfDay? picked = await showTimePicker(
    context: context,
    initialTime: TimeOfDay.now(),
    helpText: '选择时间',
    cancelText: '取消',
    confirmText: '确定',
  );

  if (picked != null) {
    setState(() {
      _selectedTime = picked;
    });
  }
}

9. showDialog 自定义对话框

创建自定义样式的对话框。

📐 自定义对话框效果

操作成功
您的操作已成功完成
确定

使用 Dialog 组件实现完全自定义的样式

showDialog(
  context: context,
  builder: (context) => Dialog(
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(16),
    ),
    elevation: 0,
    backgroundColor: Colors.transparent,
    child: Container(
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(16),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.1),
            blurRadius: 10,
            spreadRadius: 5,
          ),
        ],
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          const Icon(
            Icons.check_circle,
            color: Colors.green,
            size: 60,
          ),
          const SizedBox(height: 20),
          const Text(
            '操作成功',
            style: TextStyle(
              fontSize: 20,
              fontWeight: FontWeight.bold,
            ),
          ),
          const SizedBox(height: 10),
          const Text(
            '您的操作已成功完成',
            style: TextStyle(color: Colors.grey),
          ),
          const SizedBox(height: 20),
          ElevatedButton(
            onPressed: () => Navigator.pop(context),
            style: ElevatedButton.styleFrom(
              backgroundColor: Colors.green,
              minimumSize: const Size(double.infinity, 48),
            ),
            child: const Text('确定'),
          ),
        ],
      ),
    ),
  ),
);

🔀 对话框选择流程图

需要提示用户
信息类型?
轻量提示
SnackBar
简单确认
AlertDialog
底部操作
BottomSheet
完成选择

📊 对话框组件对比

Flutter 对话框组件对比表
组件 位置 内容 使用场景
AlertDialog 屏幕中央 简单 确认对话框
BottomSheet 底部 丰富 底部菜单/表单
SnackBar 底部 轻量 提示消息
SimpleDialog 屏幕中央 选项 选项选择
ModalBarrier 全屏 遮罩 背景遮罩

对话框最佳实践

  • 对话框应该简洁明了,不要包含过多信息
  • 为对话框提供清晰的标题和操作按钮
  • 使用 SnackBar 显示轻量级提示
  • BottomSheet 适合显示大量内容或复杂表单
  • 为对话框提供合适的动画效果
  • 确保对话框在不同设备上都能正常显示
  • 使用 Material Design 3 的对话框样式
  • 为危险操作提供明确的警告
提示:使用 showAboutDialog 可以显示应用信息。
下一步:掌握对话框组件后,继续学习动画组件。