Flutter圈子Flutter教程网

Flutter 利用OverlayEntry实现Toast

2019-12-24  本文已影响0人  头发还没秃

Flutter 利用OverlayEntry实现Toast(进阶)

在拿到一个需求或者想实现某些控件后,我们需要养成一些好习惯,比如在正式写代码前,我们有必要首先捋清楚我们的需求或者控件需要实现的一些功能:

上面的功能点列出来之后,我们就能大概的知道需要的那些参数、方法和使用的Widget:


import 'dart:async';
import 'package:flutter/material.dart';

enum Position {
  TOP,
  CENTER,
  BOTTOM,
}

class Toast {

  static OverlayEntry _overlayEntry; // 浮层,Toast显示全靠它
  static Position _toastPosition;    // 显示位置

  static void show(
    BuildContext context,
    {
      String message,// 文本内容
      Color color = Colors.black,
      Color textColor = Colors.white, // 文本颜色
      double textSize = 14.0,// 文字大小
      int seconds = 2, // 显示时长,单位:秒
      Position position = Position.BOTTOM, // 显示位置
    }
  ) async {
    assert(message != null);
    _toastPosition = position;

    //显示之前先把之前的浮层清空
    _cancelToast();
    //获取OverlayState
    OverlayState overlayState = Overlay.of(context);
    _overlayEntry = OverlayEntry(
      builder: (BuildContext context) => Positioned(
        //top值,可以改变这个值来改变toast在屏幕中的位置
        top: _getToastPosition(context),
        child: Container(
          alignment: Alignment.center,
          width: MediaQuery.of(context).size.width,
          child: Padding(
            padding: EdgeInsets.symmetric(horizontal: 40.0),
            child: Center(
              child: Card(
                color: color,//背景色
                child: Padding(
                  padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
                  child: Text(
                    message,
                    style: TextStyle(
                      fontSize: textSize,
                      color: textColor,
                    ),
                  ),
                ),
              ),
            ),
          ),
        )
      ),
    );
    overlayState.insert(_overlayEntry);
  }

  // 移除Toast
  static _cancelToast() async {
    _overlayEntry?.remove();
    _overlayEntry = null;
  }

  // 设置toast位置
  static double _getToastPosition(context) {
    double position;
    if(_toastPosition == Position.TOP){
      position = MediaQuery.of(context).size.height * 1 / 6;
    }else if(_toastPosition == Position.CENTER){
      position = MediaQuery.of(context).size.height * 3 / 6;
    }else{
      position = MediaQuery.of(context).size.height * 5 / 6;
    }
    return position;
  }
}

以上我们就实现了一个简单的能显示文本和显示位置的Toast,调用:

Toast.show(context, message: "我是一个toast", position: Position.BOTTOM);

接下来我们就为Toast添加一个计时器,让Toast能在显示时间到了后自动关闭


import 'dart:async';
import 'package:flutter/material.dart';

enum Position {
  TOP,
  CENTER,
  BOTTOM,
}

class Toast {

  static OverlayEntry _overlayEntry; // 浮层,Toast显示全靠它
  static Position _toastPosition;    // 显示位置
  static Timer _mTimer;      // 计时,如果计时大于 _seconds,则移除Toast
  static int _seconds;               // 显示时长,单位:秒

  static void show(
    BuildContext context,
    {
      String message,
      Widget child,
      Color color = Colors.black,
      Color textColor = Colors.white,
      double textSize = 14.0,
      int seconds = 2,
      Position position = Position.BOTTOM,
    }
  ) async {
    assert(message != null);
    _toastPosition = position;
    _seconds = seconds;

    //显示之前先把之前的浮层清空
    _cancelToast();
    //获取OverlayState
    OverlayState overlayState = Overlay.of(context);
    _overlayEntry = OverlayEntry(
      builder: (BuildContext context) => Positioned(
        //top值,可以改变这个值来改变toast在屏幕中的位置
        top: _getToastPosition(context),
        child: Container(
          alignment: Alignment.center,
          width: MediaQuery.of(context).size.width,
          child: Padding(
            padding: EdgeInsets.symmetric(horizontal: 40.0),
            child: Center(
              child: Card(
                color: color,//背景色
                child: Padding(
                  padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
                  child: Text(
                    message,
                    style: TextStyle(
                      fontSize: textSize,
                      color: textColor,
                    ),
                  ),
                ),
              ),
            ),
          ),
        )
      ),
    );
    _startTimer();
    overlayState.insert(_overlayEntry);
  }

  // 开启倒计时
  static void _startTimer() {
    _cancelTimer();
    _mTimer =  Timer.periodic(Duration(seconds: 1), (timer) {
      if (timer.tick > _seconds) {
        _cancelTimer();
        _cancelToast();
      }
    });
  }

  // 取消倒计时
  static _cancelTimer() async {
    _mTimer?.cancel();
    _mTimer= null;
  }

  // 移除Toast
  static _cancelToast() async {
    _overlayEntry?.remove();
    _overlayEntry = null;
  }

  // 设置toast位置
  static double _getToastPosition(context) {
    double position;
    if(_toastPosition == Position.TOP){
      position = MediaQuery.of(context).size.height * 1 / 6;
    }else if(_toastPosition == Position.CENTER){
      position = MediaQuery.of(context).size.height * 3 / 6;
    }else{
      position = MediaQuery.of(context).size.height * 5 / 6;
    }
    return position;
  }

}

以上我们就实现了我们列出来的Toast的所有功能点,代码很简单,也就那么几行,没太多可以说的

虽然我们已经实现了一个可以显示文本的Toast,但是有时候我们也想自定义显示内容,比如文本前面加个图片,文本上面加个图片等等

import 'dart:async';
import 'package:flutter/material.dart';

enum Position {
  TOP,
  CENTER,
  BOTTOM,
}

class Toast {

  static OverlayEntry _overlayEntry; // 浮层,Toast显示全靠它
  static String _message;            // 文本内容
  static Color _textColor;           // 文本颜色
  static double _textSize;           // 文字大小
  static Position _toastPosition;    // 显示位置
  static Timer _countdownTimer;      // 计时器,如果计时大于 _seconds,则移除Toast
  static int _seconds;               // 显示时长,单位:秒

  static void show(
    BuildContext context,
    {
      String message,
      Widget child,//自定义内容Widget
      Color color = Colors.black,
      Color textColor = Colors.white,
      double textSize = 14.0,
      int seconds = 2,
      Position position = Position.BOTTOM,
    }
  ) async {
    assert(message != null || child != null);
    _message = message;
    _textColor = textColor;
    _textSize = textSize;
    _seconds = seconds;
    _toastPosition = position;

    //显示之前先把之前的浮层清空
    _cancelToast();
    //获取OverlayState
    OverlayState overlayState = Overlay.of(context);
    _overlayEntry = OverlayEntry(
      builder: (BuildContext context) => Positioned(
        //top值,可以改变这个值来改变toast在屏幕中的位置
        top: _getToastPosition(context),
        child: Container(
          alignment: Alignment.center,
          width: MediaQuery.of(context).size.width,
          child: Padding(
            padding: EdgeInsets.symmetric(horizontal: 40.0),
            child: Center(
              child: Card(
                color: color,
                child: Padding(
                  padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
                  child: child != null ? child : _contentWidget(),//使用自定义内容或者默认文本内容
                ),
              ),
            ),
          ),
        )
      ),
    );
    _startTimer();
    overlayState.insert(_overlayEntry);
  }

  // 创建content widget
  static Widget _contentWidget() {
    return Text(
      _message,
      style: TextStyle(
        fontSize: _textSize,
        color: _textColor,
      ),
    );
  }

  // 开启倒计时
  static void _startTimer() {
    _cancelTimer();
    _countdownTimer =  Timer.periodic(Duration(seconds: 1), (timer) {
      if (timer.tick > _seconds) {
        _cancelTimer();
        _cancelToast();
      }
    });
  }

  // 取消倒计时
  static _cancelTimer() async {
    _countdownTimer?.cancel();
    _countdownTimer = null;
  }

  // 移除Toast
  static _cancelToast() async {
    _overlayEntry?.remove();
    _overlayEntry = null;
  }

  // 设置toast位置
  static double _getToastPosition(context) {
    double position;
    if(_toastPosition == Position.TOP){
      position = MediaQuery.of(context).size.height * 1 / 6;
    }else if(_toastPosition == Position.CENTER){
      position = MediaQuery.of(context).size.height * 3 / 6;
    }else{
      position = MediaQuery.of(context).size.height * 5 / 6;
    }
    return position;
  }

}
import 'package:flutter/material.dart';
//自定义内容
Widget customToastContent(String message, {double textSize = 14, Color textColor = Colors.white}) {
  return Row(
    mainAxisSize: MainAxisSize.min,
    mainAxisAlignment: MainAxisAlignment.center,
    crossAxisAlignment: CrossAxisAlignment.center,
    children: <Widget>[
      Icon(Icons.info, color: Colors.blue, size: 25,),
      Flexible(child: Padding(
        padding: EdgeInsets.only(left: message.isEmpty ? 0 : 10),
        child: Text(message, style: TextStyle(fontSize: textSize, color: textColor),),
      ))
    ],
  );
}

使用:

//默认文本Toast
Toast.show(context, message: "我是一个toast",);

//自定义Toast
Toast.show(context, child: customToastContent("我是一个自定义toast"), color: Colors.red);

最终效果图

111.gif
上一篇 下一篇

猜你喜欢

热点阅读