【Flutter入门到进阶】Flutter基础篇---弹窗Dialog

1 AlertDialog

1.1 说明

        最简单的方案是利用AlertDialog组件构建一个弹框

1.2 示例

void alertDialog(BuildContext context) async {
  var result = await showDialog(
      barrierDismissible: false, //表示点击灰色背景的时候是否消失弹出框
      context: context,
      builder: (context) {
        return AlertDialog(
          title: const Text("提示信息!"),
          content: const Text("您确定要删除吗"),
          actions: [
            TextButton(
                onPressed: () {
                  print("ok");
                  Navigator.of(context).pop("ok"); //点击按钮让AlertDialog消失
                },
                child: const Text("确定")),
            TextButton(
                onPressed: () {
                  print("cancel");
                  Navigator.of(context).pop("取消");
                },
                child: const Text("取消"))
          ],
        );
      });

  print("-----------");
  print(result);
}

2 SimpleDialog

2.1 说明

        通过SimpleDialog构建一个选择框

2.2 示例

void simpleDialog(BuildContext context) async {
  var result = await showDialog(
      barrierDismissible: false, //表示点击灰色背景的时候是否消失弹出框
      context: context,
      builder: (context) {
        return SimpleDialog(
          title: const Text("请选择语言"),
          children: [
            SimpleDialogOption(
              onPressed: () {
                print("汉语");
                Navigator.pop(context, "汉语");
              },
              child: const Text("汉语"),
            ),
            const Divider(),
            SimpleDialogOption(
              onPressed: () {
                print("英语");
                Navigator.pop(context, "英语");
              },
              child: const Text("英语"),
            ),
            const Divider(),
            SimpleDialogOption(
              onPressed: () {
                print("日语");
                Navigator.pop(context, "日语");
              },
              child: const Text("日语"),
            ),
            const Divider(),
          ],
        );
      });
  print("-----------");
  print(result);
}

3 自定义Flutter Dialog 

3.1 说明

        通过继承Dialog实现自定义的弹窗

3.2 示例

// 自定义dialog
class MyDialog extends Dialog {
  String title;
  String content;
  Function()? onClosed;

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

  @override
  Widget build(BuildContext context) {
    return Material(
      type: MaterialType.transparency,
      child: Center(
          child: Container(
            height: 300,
            width: 300,
            color: Colors.white,
            child: Column(
              children: [
                Padding(
                  padding: const EdgeInsets.all(10),
                  child: Stack(
                    children: [
                      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),
                )
              ],
            ),

          )),
    );
  }
}

4 Flutter Toast

4.1 第三方框架

4.1.1 说明        

        https://pub.dev/packages/fluttertoast

4.1.2 示例

Fluttertoast.showToast(
                  msg: "提示信息",
                  toastLength: Toast.LENGTH_LONG,   //值针对 android 平台
                  timeInSecForIosWeb: 1,  //提示时间 针对ios 和 web
                  backgroundColor: Colors.black26, //背景颜色
                  textColor: Colors.white,   //文本颜色
                  fontSize: 16.0  //文本字体大小
              );

4.2 自定义

4.2.1 说明

        所谓toast框其实就是在图层的最上面一层插入一个显示图层,在Flutter中利用OverLayEntry构建图层,然后通过Overlay进行插入

4.2.2 示例

import 'package:flutter/material.dart';

class Toast {
  static var _lastMsg;

  static int _lastShowms = 0;

  static get flag => true;

  static OverlayEntry? entry;
  static Future _show(BuildContext context, String msg, int duration) {
    entry = OverlayEntry(
        builder: (BuildContext context) => Positioned(
              //top值,可以改变这个值来改变toast在屏幕中的位置
              top: MediaQuery.of(context).size.height.toDouble() * 0.5,
              child: Container(
                    alignment: Alignment.center,
                    width: MediaQuery.of(context).size.width,
                    child: Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 10.0),
                      child: ToastWidget(msg: "test",duration: duration,),
                      // child: _buildToastWidget(context,msg),
                    )
                ),
              ),
    );

    ///往Overlay中插入插入OverlayEntry
    Overlay.of(context)?.insert(entry!);

    ///两秒后,移除Toast
    // Future result = Future.delayed(Duration(milliseconds: duration)).then((value) {
    //   print("移除....");
    //   entry!.remove();
    // });
    // return result;
    return Future(() => 0);
  }

  //toast UI绘制
  static _buildToastWidget(context, String msg) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Container(
            alignment: Alignment.center,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(12.0),
              shape: BoxShape.rectangle,
              color: Colors.black45,
            ),
            child: Padding(
              padding: const EdgeInsets.all(10),
              child: Text(
                  msg,
                  style: const TextStyle(
                      color: Colors.white,
                      decoration: TextDecoration.none,
                      fontSize: 14)
              ),
            )
        )
      ],
    );
  }

  //处理重复多次点击
  static void _handleDuplicateAndShow(
      String message, BuildContext context, int duration) {
    if (_lastMsg == message) {
      //相同信息内容
      int currentms = DateTime.now().millisecondsSinceEpoch;
      int interval = currentms - _lastShowms;
      if (interval > duration) {
        //大于时间间隔 可以显示
        _show(context, message, duration);
        _lastShowms = currentms;
      }
    } else {
      _show(context, message, duration);
      _lastMsg = message;
    }
  }

  /// 提示
  static void showInfo(String message, {required BuildContext context, int duration = 2000}) {
    _handleDuplicateAndShow(message, context, duration);
  }
}


class ToastWidget extends StatefulWidget {
  String msg;

  int duration;



  ToastWidget({super.key,required this.msg,required this.duration});


  @override
  State createState() => _ToastState();
}

class _ToastState extends State with SingleTickerProviderStateMixin {

  late AnimationController _controller;

  @override
  void initState() {

    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 1),
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    //启动正序一次
    Future((){
      print("启动动画...");
      _controller.forward();
    }).then((value) {
      //结束倒叙一次
      Future.delayed(Duration(milliseconds: widget.duration-2)).then((value) async{
        print("启动结束动画...");
        await _controller.reverse();
        //移除图层
        Toast.entry!.remove();
        print("移除图层...");
      });
    });

    print("构建组件");
    return Center(
      child: FadeTransition(
        opacity: _controller,
        child:Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            Container(
                alignment: Alignment.center,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(12.0),
                  shape: BoxShape.rectangle,
                  color: Colors.black45,
                ),
                child: Padding(
                  padding: const EdgeInsets.all(10),
                  child: Text(
                      widget.msg,
                      style: const TextStyle(
                          color: Colors.white,
                          decoration: TextDecoration.none,
                          fontSize: 14)
                  ),
                )
            )
          ],
        ),

      ),
    );
  }
}