Flutter 学习之旅 之 flutter 不使用插件,简单实现一个 Toast 功能
目录
[Flutter 学习之旅 之 flutter 不使用插件,简单实现一个 Toast 功能](#Flutter 学习之旅 之 flutter 不使用插件,简单实现一个 Toast 功能)
[二、简单介绍 Toast](#二、简单介绍 Toast)
[1. 确保正确配置 navigatorKey](#1. 确保正确配置 navigatorKey)
[2. 避免重复显示 Toast](#2. 避免重复显示 Toast)
[3. 确保 Toast 的上下文正确](#3. 确保 Toast 的上下文正确)
[4. 注意 Toast 的显示时长](#4. 注意 Toast 的显示时长)
一、简单介绍
Flutter 是一款开源的 UI 软件开发工具包,由 Google 开发和维护。它允许开发者使用一套代码同时构建跨平台的应用程序,包括移动设备(iOS 和 Android)、Web 和桌面平台(Windows、macOS 和 Linux)。
Flutter 使用 Dart 编程语言,它可以将代码编译为 ARM 或 Intel 机器代码以及 JavaScript,从而实现快速的性能。Flutter 提供了一个丰富的预置小部件库,开发者可以根据自己的需求灵活地控制每个像素,从而创建自定义的、适应性强的设计,这些设计在任何屏幕上都能呈现出色的外观和感觉。

二、简单介绍 Toast
在 Flutter 中,不使用 Toast 插件,可以通过 Overlay
和 Timer
实现简单 Toast 功能。创建一个透明的 OverlayEntry
,在其上显示自定义文本,设置显示时长后自动隐藏。这种方式无需额外依赖,灵活且轻量,适用于快速提示信息。
需要注意以下几点:
1. 确保正确配置 navigatorKey
-
Toast
功能依赖于navigatorKey
来获取OverlayState
,因此必须在MaterialApp
中绑定navigatorKey
:dart复制
MaterialApp( navigatorKey: Toast.navigatorKey, ... );
-
如果未绑定
navigatorKey
,Toast.show
方法会打印错误信息,并且无法显示 Toast。
2. 避免重复显示 Toast
-
当用户快速多次点击按钮时,可能会导致多个 Toast 同时显示。可以通过以下方式解决:
-
在显示 Toast 时设置一个标志位,避免重复调用。
-
或者在显示新 Toast 时,先移除已存在的 Toast。
-
3. 确保 Toast 的上下文正确
-
Toast.show
方法通过Overlay
显示,因此必须在包含MaterialApp
的上下文中调用。 -
如果在
MaterialApp
之外调用Toast.show
,会导致OverlayState
为null
。
4. 注意 Toast 的显示时长
-
默认情况下,Toast 的显示时长为 2 秒(
Duration(seconds: 2)
)。如果需要更长或更短的显示时间,可以通过duration
参数自定义:dart复制
Toast.show("这是一条消息", duration: Duration(seconds: 3));
-
如果显示时长过短,用户可能无法看清内容;如果过长,可能会影响用户体验。
三、简单案例实现
1、这里使用 Android Studio 进行创建 Flutter 项目

2、创建一个 application 的 Flutter 项目

3、编写代码,进行简单 Toast 功能实现

4、在 main 中添加测试 Toast 的 代码

5、连接设备,或者 web ,运行效果如下

四、关键代码
1、toast.dart
Dart
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
// 定义 Toast 的显示位置枚举
enum ToastPosition { top, center, bottom }
class Toast {
// 定义一个全局的 NavigatorState 键,用于获取 OverlayState
static final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
// Toast 显示方法
static void show(
String message, {
ToastPosition position = ToastPosition.bottom, // 默认显示在底部
Duration duration = const Duration(seconds: 2), // 默认显示时长为 2 秒
}) {
// 获取当前的 OverlayState
final OverlayState? overlayState = navigatorKey.currentState?.overlay;
// 如果 OverlayState 为空,说明未正确设置 MaterialApp 的 navigatorKey
if (overlayState == null) {
print("OverlayState is null. Make sure to use MaterialApp with navigatorKey.");
return;
}
// 创建一个 OverlayEntry,用于显示 Toast
final OverlayEntry overlayEntry = OverlayEntry(
builder: (context) {
// 根据 position 参数设置 Toast 的对齐方式
return Align(
alignment: position == ToastPosition.center
? Alignment.center // 显示在屏幕中央
: position == ToastPosition.top
? Alignment.topCenter // 显示在顶部
: Alignment.bottomCenter, // 显示在底部
child: Padding(
padding: EdgeInsets.only(
top: position == ToastPosition.top ? 20 : 0, // 距离顶部 20px
bottom: position == ToastPosition.bottom ? 20 : 0, // 距离底部 20px
),
child: Material(
elevation: 4, // 添加阴影效果
borderRadius: BorderRadius.circular(50), // 设置为半圆形状
child: Container(
constraints: BoxConstraints(minWidth: 100, maxWidth: 300), // 限制 Toast 的宽度
padding: EdgeInsets.all(16), // 内边距
decoration: BoxDecoration(
color: Colors.black87, // 背景颜色
borderRadius: BorderRadius.circular(50), // 设置为半圆形状
),
child: Text(
message, // 显示的文本内容
style: TextStyle(color: Colors.white, fontSize: 16), // 文本样式
textAlign: TextAlign.center, // 文本居中
softWrap: true, // 自动换行
maxLines: null, // 不限制行数
),
),
),
),
);
},
);
// 将 OverlayEntry 插入到 Overlay 中,显示 Toast
overlayState.insert(overlayEntry);
// 使用 SchedulerBinding 添加一个后帧回调
SchedulerBinding.instance.addPostFrameCallback((_) {
// 在指定的 duration 时间后移除 OverlayEntry,隐藏 Toast
Future.delayed(duration).then((_) {
overlayEntry.remove();
});
});
}
}
代码说明:
ToastPosition
枚举:定义了 Toast 的显示位置(顶部、中央、底部)。
navigatorKey
:用于获取当前MaterialApp
的NavigatorState
,从而获取OverlayState
。
show
方法:
接收
message
参数(显示的文本)和可选参数(位置和显示时长)。检查
OverlayState
是否为空,确保MaterialApp
已正确配置。创建
OverlayEntry
并根据位置参数设置对齐方式。使用
Material
和Container
构造 Toast 的样式,包括背景颜色、阴影、圆角和文本样式。将
OverlayEntry
插入到Overlay
中,显示 Toast。使用
SchedulerBinding
和Future.delayed
在指定时长后移除 Toast。
2、main.dart
Dart
import 'package:flutter/material.dart';
import 'toast.dart'; // 导入封装的 Toast 工具类,用于显示自定义 Toast
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Toast Demo', // 应用的标题
navigatorKey: Toast.navigatorKey, // 将全局的 navigatorKey 绑定到 MaterialApp
home: Scaffold( // 主页面布局
appBar: AppBar( // 应用栏
title: Text('Flutter Toast Demo'), // 标题
),
body: Center( // 主体内容居中
child: Column( // 垂直布局
mainAxisAlignment: MainAxisAlignment.center, // 子组件垂直居中
children: [
ElevatedButton( // 按钮,点击后显示顶部 Toast
onPressed: () {
Toast.show(
"这是一条顶部 Toast辅导费地方东方饭店", // 要显示的文本
position: ToastPosition.top, // 设置 Toast 显示在顶部
);
},
child: Text('显示顶部 Toast'), // 按钮文本
),
SizedBox(height: 20), // 间距
ElevatedButton( // 按钮,点击后显示中间 Toast
onPressed: () {
Toast.show(
"这是一条中间 Toast", // 要显示的文本
position: ToastPosition.center, // 设置 Toast 显示在中间
);
},
child: Text('显示中间 Toast'), // 按钮文本
),
SizedBox(height: 20), // 间距
ElevatedButton( // 按钮,点击后显示底部 Toast
onPressed: () {
Toast.show(
"这是一条底部 Toast", // 要显示的文本
position: ToastPosition.bottom, // 设置 Toast 显示在底部
);
},
child: Text('显示底部 Toast'), // 按钮文本
),
],
),
),
),
);
}
}
代码说明:
导入模块:
import 'toast.dart';
:导入封装好的 Toast 工具类,用于实现自定义 Toast 功能。
MyApp
类:
MaterialApp
:Flutter 的根组件,用于配置主题和路由。
navigatorKey: Toast.navigatorKey
:将Toast
类中定义的全局navigatorKey
绑定到MaterialApp
,以便通过navigatorKey
获取OverlayState
,这是显示 Toast 的关键。
Scaffold
:
Scaffold
是 Flutter 中用于构建页面布局的基础组件,包含appBar
和body
。
appBar
:显示页面的标题。
body
:页面的主体内容,使用Center
和Column
布局,将按钮垂直居中。按钮功能:
每个按钮通过
onPressed
回调调用Toast.show
方法。
Toast.show
方法接收一个字符串(要显示的文本)和一个可选参数position
(指定 Toast 的显示位置:顶部、中间、底部)。示例中分别展示了如何调用顶部、中间和底部的 Toast。