# Flutter教程 - 7 Dialog和Toast

在开发 App 的时候,各种弹出窗口和提示内容是必不可少的,下面就来学习一下 Flutter 中常用的一些弹出窗口和提示展示的 Toast

# 7.1 AlertDialog

显示效果如下:

实现代码如下:

在上面的实现中,是先在页面中添加了一个 ElevatedButton 按钮,然后点击按钮,触发 AlertDialog 的显示。

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DemoPage(),
    );
  }
}

/// 页面
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        child: ElevatedButton(
            onPressed: () {
              // -------------通过showDialog显示AlertDialog----------------
              showDialog(
                  barrierDismissible: false, //表示点击灰色背景的时候是否消失弹出框
                  context: context,
                  builder: (context) {
                    // ---- 返回一个AlertDialog
                    return AlertDialog(
                      title: const Text("提示信息"),
                      content: const Text("您确定要删除吗?"),
                      // ---- 添加两个按钮
                      actions: <Widget>[
                        TextButton(
                          child: const Text("取消"),
                          onPressed: () {
                            print("点击了取消按钮");

                            Navigator.pop(context); // 关闭窗口
                          },
                        ),
                        TextButton(
                          child: const Text("确定"),
                          onPressed: () {
                            print("点击了确定按钮");
                            Navigator.pop(context);     // 关闭窗口
                          },
                        )
                      ],
                    );
                  });
            },
            child: const Text("AlertDialog")),
      ),
    );
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

在上面的代码中,点击 ElevatedButton 按钮,调用了 showDialog 方法,showDialog 方法的 builder 参数是一个 WidgetBuilder,方法需要返回一个 Widget, 这里返回一个 AlertDialog,在 AlertDialog 中添加了两个文本按钮 TextButton ,一个是取消,一个是确定

当点击确定和取消按钮的时候,Dialog 是不会自己消失的,需要调用 Navigator.pop(context) 关闭 Dialog

# 7.2 SimpleDialog

先看效果:

实现代码:

首先是在页面上添加了一个按钮,点击按钮,弹出 SimpleDialog

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DemoPage(),
    );
  }
}

/// 页面
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        child: ElevatedButton(
            onPressed: () {
              // -------------显示SimpleDialog----------------
              showDialog(
                  barrierDismissible: true, //表示点击灰色背景的时候是否消失弹出框
                  context: context,
                  builder: (context) {
                    // ---- 创建SimpleDialog
                    return SimpleDialog(
                      title: const Text("请选择"),
                      // ---- children是各个选项,这里使用的是SimpleDialogOption创建
                      children: <Widget>[
                        SimpleDialogOption(
                          child: const Text("选项一"),
                          onPressed: () {
                            print("点击了选项一");
                            Navigator.pop(context);     // 关闭窗口
                          },
                        ),
                        const Divider(),
                        SimpleDialogOption(
                          child: const Text("选项二"),
                          onPressed: () {
                            print("点击了选项二");
                            Navigator.pop(context);     // 关闭窗口
                          },
                        ),
                        const Divider(),
                        SimpleDialogOption(
                          child: const Text("选项三"),
                          onPressed: () {
                            print("点击了选项三");
                            Navigator.pop(context);     // 关闭窗口
                          },
                        ),
                      ],
                    );
                  });
            },
            child: const Text("SimpleDialog")),
      ),
    );
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

同样还是使用 showDialog 方法来显示 SimpleDialogSimpleDialog 中的 children 属性是弹出窗口的各个选项。

# 7.3 showModalBottomSheet

在前面弹出 Dialog 都是使用 showDialog 方法,实在屏幕中间弹出的,还可以使用 showModalBottomSheet 方法,在屏幕底部弹出。

先看效果:

点击按钮,从屏幕底部展示。

实现代码:

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DemoPage(),
    );
  }
}

/// 页面
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        child: ElevatedButton(
            onPressed: () {
              // -------------在屏幕底部显示----------------
              showModalBottomSheet(
                  context: context,
                  builder: (context) {
                    // ---- 创建Widget用于显示
                    return SizedBox(
                      height: 220,
                      child: Column(
                        children: <Widget>[
                          ListTile(
                            title: const Text("点赞"),
                            onTap: () {
                              print("点击了点赞");
                              Navigator.pop(context);
                            },
                          ),
                          const Divider(),
                          ListTile(
                            title: const Text("转发"),
                            onTap: () {
                              print("点击了转发");
                              Navigator.pop(context);
                            },
                          ),
                          const Divider(),
                          ListTile(
                            title: const Text("收藏"),
                            onTap: () {
                              print("点击了收藏");
                              Navigator.pop(context);
                            },
                          )
                        ],
                      ),
                    );
                  });
            },
            child: const Text("showModalBottomSheet")),
      ),
    );
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

使用 showModalBottomSheet 方法,展示弹出窗口,showModalBottomSheet 方法中的 builder 参数用来构建展示的 Widget,可以根据自己的需要进行布局和创建,这里是添加了三个ListTile

# 7.4 Dialog 返回的内容

在前面,调用 showDialogshowModalBottomSheet 方法的时候,是没有返回值的,我们也可以使用 Navigator.pop(context, "值") 来返回值。

举个栗子:

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DemoPage(),
    );
  }
}

/// 页面
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  void _showAlertDialog(BuildContext context) async {
    // -------------通过showDialog显示AlertDialog----------------
    var result = await showDialog(
        barrierDismissible: false, //表示点击灰色背景的时候是否消失弹出框
        context: context,
        builder: (context) {
          // ---- 返回一个AlertDialog
          return AlertDialog(
            title: const Text("提示信息"),
            content: const Text("您确定要删除吗?"),
            // ---- 添加两个按钮
            actions: <Widget>[
              TextButton(
                child: const Text("取消"),
                onPressed: () {
                  print("点击了取消按钮");
                  Navigator.pop(context, "取消"); // 关闭窗口,同时传值
                },
              ),
              TextButton(
                child: const Text("确定"),
                onPressed: () {
                  print("点击了确定按钮");
                  Navigator.pop(context, "确定"); // 关闭窗口,同时传值
                },
              )
            ],
          );
        });

    print("result:$result");	// 点击确定按钮时,打印确定,点击取消按钮时,打印取消
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        child: ElevatedButton(
            onPressed: () {
              _showAlertDialog(context);
            },
            child: const Text("AlertDialog")),
      ),
    );
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

在上面的代码中,我们先定义了一个私有方法 _showAlertDialog 该方法是一个 async 方法,在调用 showDialog 显示 Dialog 的时候,使用了 await ,这样会等待 showDialog 方法的返回结果。而 showDialog 方法的返回结果,是通过 Navigator.pop(context, "值") 来返回的,所以当调用 Navigator.pop(context, "值") 的时候,会将 "值" ,传递给 result 变量。

# 7.5 自定义Dialog

在上面我们使用了几种系统自带的 Dialog,但有些时候可能不满足我们的需求,所以我们可以自定义 Dialog

自定义 Dialog 对象,需要继承 Dialog 类,并重写 build 函数。下面演示一下如何自定义 Dialog

举个栗子:

先看效果,简单的定义了一个弹出窗口。

实现代码:

# 1 定义 Dialog

首先定义了一个自定义的 MyDialog 类,继承自 Dialog 类。然后定义了三个属性,title 用来显示标题,content 用来显示内容,onClosed 是点击关闭按钮后的回调函数。Function()? 表示无参函数。

my_dialog.dart

import 'package:flutter/material.dart';

class MyDialog extends Dialog {
  // 接收标题
  String title;

  // 接收内容
  String content;

  // 接收关闭按钮的回调函数
  Function()? onClosed;

  MyDialog({Key? key,
      required this.title,
      required this.onClosed,
      this.content = ""})
      : super(key: key);

  
  Widget build(BuildContext context) {
    return Material(
      // 定义显示是透明的
      type: MaterialType.transparency,
      // center 会铺满整个屏幕
      child: Center(
          child: Container(
        height: 300,
        width: 300,
        color: Colors.white,
        child: Column(
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(10),
              child: Stack(
                // ---- 定义标题和关闭按钮
                children: <Widget>[
                  Align(
                    alignment: Alignment.center,
                    child: Text(title),
                  ),
                  Align(
                    alignment: Alignment.centerRight,
                    child: InkWell(
                      onTap: onClosed,
                      child: const Icon(Icons.close),
                    ),
                  )
                ],
              ),
            ),
            const Divider(),
            // ---- 定义显示的内容
            Container(
              padding: const EdgeInsets.all(10),
              width: double.infinity,
              child: Text(content, textAlign: TextAlign.left),
            )
          ],
        ),
      )),
    );
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

Dialog 根组件使用的是 Material 组件,通过 type 来设置整个窗口的透明度,其中的 child 属性中的 Center 是全屏显示的。Container 才是弹出的窗口部分,可以根据需要进行布局。

# 2 显示 Dialog

显示 Dialog 也之前显示 AlertDialog 一样,也是使用的 showDialog 方法,当然在使用之前,先引入刚才自定义 Dialog 的文件。

main.dart

import 'package:flutter/material.dart';
// ----1.引入自定义的Dialog
import './my_dialog.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DemoPage(),
    );
  }
}

/// 页面
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        child: ElevatedButton(
            onPressed: () {
              // ----2.显示自定义的Dialog
              showDialog(
                  barrierDismissible: false, //表示点击灰色背景的时候是否消失弹出框
                  context: context,
                  builder: (context) {
                    // ----3.创建自定义的Dialog并传入参数
                    return MyDialog(
                        title: '标题',
                        onClosed: () {
                          print("关闭");
                          Navigator.of(context).pop();
                        },
                        content: "我是一个内容");
                  });
            },
            child: const Text("自定义Dialog")),
      ),
    );
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# 3 自动关闭

如果想要上面自定义的 Dialog 间隔 3 秒自动关闭该如何实现呢?

可以定义一个定时器,用来3秒后关闭窗口。

举个栗子:

import 'dart:async';

import 'package:flutter/material.dart';

class MyDialog extends Dialog {
  // 接收标题
  String title;

  // 接收内容
  String content;

  // 接收关闭按钮的回调函数
  Function()? onClosed;

  // ---- 使用定时器定时关闭窗口
  void _showTimer(context){
    Timer.periodic(Duration(milliseconds: 3000), (t) {
      print('自动关闭');
      Navigator.pop(context);
      t.cancel();
    });
  }

  MyDialog({Key? key,
      required this.title,
      required this.onClosed,
      this.content = ""})
      : super(key: key);

  
  Widget build(BuildContext context) {

   	// ---- 打开定时器
    _showTimer(context);

    return Material(
      // 定义显示是透明的
      type: MaterialType.transparency,
      // center 会铺满整个屏幕
      child: Center(
          child: Container(
        height: 300,
        width: 300,
        color: Colors.white,
        child: Column(
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(10),
              child: Stack(
                // ---- 定义标题和关闭按钮
                children: <Widget>[
                  Align(
                    alignment: Alignment.center,
                    child: Text(title),
                  ),
                  Align(
                    alignment: Alignment.centerRight,
                    child: InkWell(
                      onTap: onClosed,
                      child: const Icon(Icons.close),
                    ),
                  )
                ],
              ),
            ),
            const Divider(),
            // ---- 定义显示的内容
            Container(
              padding: const EdgeInsets.all(10),
              width: double.infinity,
              child: Text(content, textAlign: TextAlign.left),
            )
          ],
        ),
      )),
    );
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

# 7.6 Toast

Flutter 中没有内置的 Toast 组件,但你可以使用第三方库来实现 Toast 的功能。一个常用的 Toast 插件是 fluttertoast,它提供了在 Flutter 应用中显示 Toast 的功能。

可以访问 pub.dev 网站( https://pub.dev/ )进行搜索。

要使用 fluttertoast,首先需要在 pubspec.yaml 文件中添加它作为依赖:

dependencies:
  flutter:
    sdk: flutter
  fluttertoast: ^8.2.2
1
2
3
4

理论上修改 pubspec.yaml 后,保存就会自动下载依赖,如果没有的话,可以在项目下使用命令行运行 flutter pub get 来安装依赖。

Android Studio 也会弹出提示。

然后就可以在 Dart 代码中导入 fluttertoast 包并使用它来显示 Toast。

pub.dev 网站上搜索到,上面也会有使用的代码。

举个例子:

import 'package:flutter/material.dart';
// ----1.引入fluttertoast
import 'package:fluttertoast/fluttertoast.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DemoPage(),
    );
  }
}

/// 页面
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        child: ElevatedButton(
            onPressed: () {
              // ---- 2.显示Toast
              Fluttertoast.showToast(
                msg: "这是一个Toast消息",
                toastLength: Toast.LENGTH_SHORT, // Toast 显示时长
                gravity: ToastGravity.BOTTOM,    // Toast 位置
                timeInSecForIosWeb: 1,          // iOS/Web 上的显示时长
                backgroundColor: Colors.grey,   // 背景颜色
                textColor: Colors.white,        // 文本颜色
                fontSize: 16.0,                 // 文本大小
              );
            },
            child: const Text("Toast")),
      ),
    );
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

显示效果: