[Flutter]自定义等待转圈和Toast提示

1.自定义样式

2.自定义LoadingView

import 'package:flutter/material.dart';

enum LoadingStyle {
  onlyIndicator, // 仅一个转圈等待
  roundedRectangle, // 添加一个圆角矩形当背景
  maskingOperation, // 添加一个背景蒙层, 阻止用户操作
}

class LoadingView {
  static final LoadingView _singleton = LoadingView._internal();

  factory LoadingView() {
    return _singleton;
  }

  LoadingView._internal();

  OverlayEntry? _overlayEntry;  

  void show(BuildContext context, {LoadingStyle type = LoadingStyle.onlyIndicator}) {
    if (_overlayEntry == null) {
      _overlayEntry = _createOverlayEntry(type);
      Overlay.of(context).insert(_overlayEntry!);  
    }
  }

  void hide() {
    _overlayEntry?.remove();
    _overlayEntry = null;
  }

  OverlayEntry _createOverlayEntry(LoadingStyle type) => OverlayEntry(
        builder: (BuildContext context) {
          List<Widget> stackChildren = [];
          if (type == LoadingStyle.roundedRectangle) {
            stackChildren.add(
              Center(
                child: Container(
                  width: 100,
                  height: 100,
                  padding: const EdgeInsets.all(20.0),
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(8.0),
                  ),
                  child: const Align(
                    alignment: Alignment.center,
                    child: SizedBox(
                      width: 45,
                      height: 45,
                      child: CircularProgressIndicator(
                        color: Colors.black,
                      ),
                    ),
                  ),
                ),
              ),
            );
          } else if (type == LoadingStyle.maskingOperation) {
            stackChildren.addAll([
              const Opacity(
                opacity: 0.5,
                child: ModalBarrier(dismissible: false, color: Colors.black),
              ),
              const Center(child: CircularProgressIndicator()),
            ]);
          } else {
            stackChildren.add(
              const Center(child: CircularProgressIndicator()),
            );
          }

          return Stack(children: stackChildren);
        },
      );
}

3.自定义ToastView

import 'package:flutter/material.dart';

enum ToastPosition { center, bottom }

class ToastView {
  static OverlayEntry? _overlayEntry;

  static void showToast(
    BuildContext context,
    String message, {
    ToastPosition position = ToastPosition.center,
    int second = 2,
    Color backgroundColor = Colors.white,
    Color textColor = Colors.black,
    double horizontalMargin = 16,
    EdgeInsetsGeometry padding = const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
  }) {
    _overlayEntry?.remove();

    _overlayEntry = OverlayEntry(
      builder: (context) => ToastWidget(
        message: message,
        position: position,
        backgroundColor: backgroundColor,
        textColor: textColor,
        horizontalMargin: horizontalMargin,
        padding: padding,
      ),
    );

    Overlay.of(context)?.insert(_overlayEntry!);

    Future.delayed(Duration(seconds: second), () {
      _overlayEntry?.remove();
      _overlayEntry = null;
    });
  }
}

class ToastWidget extends StatelessWidget {
  final String message;
  final ToastPosition position;
  final Color backgroundColor;
  final Color textColor;
  final double horizontalMargin;
  final EdgeInsetsGeometry padding;

  const ToastWidget({
    Key? key,
    required this.message,
    required this.position,
    required this.backgroundColor,
    required this.textColor,
    required this.horizontalMargin,
    required this.padding,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Positioned(
      top: position == ToastPosition.center ? MediaQuery.of(context).size.height / 2 : null,
      bottom: position == ToastPosition.bottom ? 50.0 : null,
      left: horizontalMargin,
      right: horizontalMargin,
      child: Material(
        color: Colors.transparent,
        child: Align(
          alignment: position == ToastPosition.center ? Alignment.center : Alignment.bottomCenter,
          child: FittedBox(
            fit: BoxFit.scaleDown,
            child: Container(
              padding: padding,
              decoration: BoxDecoration(
                color: backgroundColor,
                borderRadius: BorderRadius.circular(8),
              ),
              child: Text(
                message,
                textAlign: TextAlign.center,
                style: TextStyle(
                  fontSize: 15,
                  color: textColor,
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

4.创建一个全局的回调管理AlertCallbackManager

经过上面自定义视图,我们注意到,视图的展示都需要BuildContext context。若是这样的话,就强行将弹窗视图的逻辑绑定到了具体的某个组件上,导致组件销毁时弹窗也必须销毁。否则,context都消失了,你又如何去处理插入其中的视图?

我们往往需要,让等待转圈在离开页面后还继续展示,让Toast在关闭页面时也不被影响到其提示的时长。

所以,这里我们用了一个全局回调管理。

enum AlertCallbackType { none, showLoading, hideLoading, showToast }

class AlertCallbackManager {
  // 私有构造函数
  AlertCallbackManager._privateConstructor();

  // 单例实例
  static final AlertCallbackManager _instance = AlertCallbackManager._privateConstructor();

  // 获取单例实例的方法
  static AlertCallbackManager get instance => _instance;

  // 定义闭包类型的回调函数
  Function(AlertCallbackType type, String message)? callback;
}

5.创建一个根组件,将等待加载和Toast提示当作公共逻辑来处理。

有了全局回调管理,我们还需要有一个不会被轻易销毁的根组件,来提供BuildContext context。

注意:全局提示回调, 要放在MaterialApp包装之后,因为这里的LoadingView实现方式需要放在MaterialApp之下。

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

// MARK: 用来包装MaterialApp
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false, // 禁用调试标签
      home: BaseWidget(),
    );
  }
}

// MARK: 根组件 用来处理公用逻辑
class BaseWidget extends StatefulWidget {
  const BaseWidget({super.key});

  @override
  State<BaseWidget> createState() => _BaseWidgetState();
}

class _BaseWidgetState extends State<BaseWidget> {
  @override
  void initState() {
    super.initState();
    // 提示回调, 要放在MaterialApp包装之后
    AlertCallbackManager.instance.callback = (type, message) async {
      if (mounted) { // 检查当前State是否仍然被挂载(即没有被dispose)
        if (type == AlertCallbackType.showLoading) {
          LoadingView().show(context);
        } else if (type == AlertCallbackType.hideLoading) {
          LoadingView().hide();
        } else if (type == AlertCallbackType.showToast) {
          ToastView.showToast(context, message);
        }
      }
    };
  }

  @override
  void dispose() {
    LoadingView().hide();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return const HomePage();
  }
}

然后在需要展示的地方,用如下方式调用,最好再进一步将方法封装得短一些。

AlertCallbackManager.instance.callback?.call(AlertCallbackType.showLoading, "");

AlertCallbackManager.instance.callback?.call(AlertCallbackType.hideLoading, "");
 
AlertCallbackManager.instance.callback?.call(AlertCallbackType.showToast, "message");
  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/447861.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CleanMyMac X 4.14.1中文版功能介绍及激活入口

细心的用户发现苹果Mac电脑越用越慢&#xff0c;其实这种情况是正常的&#xff0c;mac电脑用久了会产生很多的缓存文件&#xff0c;如果不及时清理会影响运行速度。macbook就会产生各种各样的垃圾文件,比如说残留的注册表或者无效的注册表,系统碎片以及毫无用处的文件等,这些的…

C++动态二维数组vector<vector<T>>详细讲解

前言 在本文章中&#xff0c;我们将要详细介绍一下C中vector关于动态二维数组vector<vector>。 一、杨辉三角的引入 我们在介绍动态二维数组之前&#xff0c;先来看一下这道题目 在本题目中&#xff0c;我们很容易发现规律&#xff0c;两边数据为1,剩下的按照一定的规…

Dynamo程序添加到Revit工具栏(懒人版)

你是不是想将Dynamo写好的程序添加到Revit工具栏&#xff1f; 你是否还在因为Dyno Browser配置起来太复杂而烦恼&#xff1f; 你是否因为Dynamo不同版本&#xff0c;无法单独配置工具栏而发愁&#xff1f; 今天九哥来给大家弄了一个更简单的工具&#xff0c;是拿网上开源的工…

巫蛊之祸——汉武帝后期的一次重大事件

引 言 “巫蛊之祸”是汉武帝在位后期发生的一次重大政治事件&#xff0c;也是西汉历史上最大的冤案&#xff0c;此案导致皇后卫子夫和太子刘据自杀&#xff0c;数万人头落地&#xff0c;几十万人被牵连。 一、巫蛊之术的由来 《汉书》记载&#xff0c;巫蛊之术起源自胡巫&am…

批量合并:一键操作,轻松将多个TXT文本合并为一个

在信息爆炸的时代&#xff0c;我们每天都面临着处理大量文本信息的挑战。无论是学习、工作还是生活中&#xff0c;TXT文件作为最基础的文本格式&#xff0c;承载着大量的重要信息。然而&#xff0c;传统的文本管理方式往往效率低下&#xff0c;难以满足我们的实际需求。那么&am…

python处理csv文件

1.使用 csv_writer.writerow # 导入CSV安装包 import csv# 1. 创建文件对象 f open(文件名.csv,a,encodingutf-8)# 2. 基于文件对象构建 csv写入对象 csv_writer csv.writer(f)# 3. 构建列表头 csv_writer.writerow(["问题","答案"])list_name[] # 4. 写…

Python之Web开发中级教程----搭建Web框架一

准备环境&#xff1a;ubuntu,Python3.6.9 一、Web应用程序的原理 接收并解析HTTP请求&#xff0c;获取客户的请求信息->处理完成请求的业务逻辑->返回处理结果HTTP响应。 Web框架的架构是这样的&#xff1a; 基于python的web框架&#xff0c;如tornado、flask、webpy都是…

【大厂AI课学习笔记NO.74】人工智能产业技术架构

包括基础层、技术层和应用层。 人工智能的产业技术架构是一个多层次、多维度的复杂系统&#xff0c;它涵盖了从基础硬件和软件设施到高级算法和应用技术的全过程。这个架构通常可以分为三个主要层次&#xff1a;基础层、技术层和应用层。下面我将详细论述这三个层次及其细分内…

GPU:使用阿里云服务器,免费部署一个开源大模型

前面提到CPU版本如何安装和部署ChatGLM&#xff0c;虽然能部署&#xff0c;但是速度和GPU比起来确实一言难尽。 然后找阿里云白嫖了一个服务器&#xff08;省点用的话&#xff0c;不用的时候关机&#xff0c;可以免费用两个多月没问题&#xff09;&#xff0c;只要没有申请过 …

中医中的虚是什么?虚的分类?如何治疗气虚?

目录 中医中虚的分类气虚&#xff08;此处指脾气虚&#xff09;症状舌象&#xff1a;舌头中间区域有裂痕 或者 舌胖有齿痕身体上 解决方法其它脏腑气虚的情况及解决方法 血虚津液不足阴虚阳虚 中医中虚的分类 图片来源于微信视频的名为 路广林主任 的视频。 气虚&#xff08;此…

使用gin框架,编写一个接收数据的api接口

功能&#xff1a;这里主要编写一个接口&#xff0c;将其json 数据存入对应的redis队列中&#xff0c;并统计每天的每小时请求数量 环境&#xff1a; go version go1.22.0 linux/amd64 平台 linux X64 步骤一 新建目录 命令如下&#xff1a; mkdir FormData 步骤二 新增…

javascript实现解决浮点数加减乘除运算误差丢失精度问题【收藏点赞】

相信程序都会遇到这样的问题&#xff0c;有时需要在js上做运算合计等浮点数加减乘除&#xff0c;但会有些浮点数会有误差问题。下面用js来解决浮点数加减乘除运算误差丢失精度这个请 【收藏点赞】。 是程序都会在浮点数加减乘除上有误差问题&#xff0c;这是计算机二进制生成的…

防御保护--第七次作业

题目 要求 在FW5和FW3之间建立一条IPSEC通道&#xff0c;保证10.0.2.0/24网段可以正常访问到192.168.1.0/24 过程 FW5 FW3

Websocket在Asp.net webApi(.net framework)上的应用

之前在写看板部分的web api的时候&#xff0c;都是通过Ajax在规定时间内轮询调用web api&#xff0c;这样简单省事&#xff0c;但是当看板多了&#xff08;并发量上来&#xff09;以后&#xff0c;比较消耗服务器的性能&#xff0c;所以最近研究了websocket&#xff0c;希望使用…

Window10数据库崩溃启动失败,MySQL8.0.30通过data文件夹恢复数据库到Docker

背景&#xff1a; 昨天关机前还在使用mysql&#xff0c;一切正常&#xff0c;但今天打开电脑&#xff0c;发现mysql启动不起来了&#xff0c;老是提示端口占用&#xff0c;但是系统也没有新安装什么软件&#xff0c;而且通过查询nat命令也没发现3306端口占用。而且修改成3307等…

【格与代数系统】格与哈斯图

【格与代数系统】格与代数系统汇总 目录 常见的偏序关系 覆盖 哈斯图 例1 例2 例3 格与哈斯图 例1 例2 常见的偏序关系 偏序关系&#xff1a;自反性反对称性传递性 整数集合上的小于等于&#xff08;大于等于&#xff09;关系、幂集中的包含关系 、正整数的整除和整…

网络原理初识(2)

目录 一、协议分层 1、分层的作用 2、OSI七层模型 3、TCP / IP五层&#xff08;或四层&#xff09;模型 4、网络设备所在分层 5、网络分层对应 二、封装和分用 发送过程&#xff08;封装&#xff09; 1、应用层(应用程序) QQ 2、传输层 3、网络层 4、数据链路层 5、物理…

AI皮肤测试的基本原理

人工智能测试皮肤的实现原理通常涉及计算机视觉和机器学习技术。以下是一般的实现步骤和原理&#xff0c;涉及数据收集、特征提取、模型训练和优化等多个步骤&#xff0c;利用这些步骤中的技术手段来实现对皮肤状况的识别和分类。北京木奇移动技术有限公司&#xff0c;专业的软…

Python 导入Excel三维坐标数据 生成三维曲面地形图(体) 5-2、线条平滑曲面且可通过面观察柱体变化(二)

环境和包: 环境 python:python-3.12.0-amd64包: matplotlib 3.8.2 pandas 2.1.4 openpyxl 3.1.2 scipy 1.12.0 代码: import pandas as pd import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from scipy.interpolate import griddata fr…

raid0、raid1、raid5、raid10选哪个?一文给你答案!

下午好&#xff0c;我的网工朋友。 关于磁盘阵列的用法&#xff0c;总有朋友对其用途与功能一知半解&#xff0c;很容易弄混。 而我们在做监控项目存储时&#xff0c;经常会用到磁盘阵列。 什么是磁盘阵列&#xff1f;为什么要做磁盘阵列&#xff1f;用什么样的磁盘阵列合适…
最新文章