在拿到一个需求或者想实现某些控件后,我们需要养成一些好习惯,比如在正式写代码前,我们有必要首先捋清楚我们的需求或者控件需要实现的一些功能:
- 利用OverlayEntry实现(关于OverlayEntry这个Widget如果有不清楚的可以自己百度一下)
- 可以设置Toast显示时间,比如显示3秒后自动移除Toast(Timer)
- 可以设置Toast显示位置,比如在顶部、中间、底部显示(Positioned)
- 可以设置Toast背景颜色
- 可以设置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
网友评论