Flutter弹窗链-顺序弹出对话框

效果

前言

弹窗的顺序执行在App中是一个比较常见的应用场景。比如进入App首页,一系列的弹窗就会弹出。如果不做处理就会导致弹窗堆积的全部弹出,严重影响用户体验。

如果多个弹窗中又有判断逻辑,根据点击后需要弹出另一个弹窗,这个弹窗优先级更高,需要在当前弹出框关闭后弹出,又添加了复杂度了,所以才会有需要管理多个弹窗的展示需求。

实现

  • 采用方式是拦截器法
/// 源码:https://github.com/yixiaolunhui/flutter_xy
/// 链式拦截器。
abstract class ChainInterceptor {/// 拦截器执行方法。void intercept(ChainHandler chain);
}/// 链
abstract class Chain {/// 将拦截器添加到链中。/// 如果提供了 [index],则在指定的索引处添加拦截器。/// 否则,将拦截器添加到链的末尾。void addChain(ChainInterceptor interceptor, {int? index});/// 执行链void proceed();
}/// 链状态监听器。
abstract class ChainStatusListener {/// 当链状态发生变化时调用。/// [isChainEnd] 表示链是否已经执行完毕。void onStatusChange(bool isChainEnd);
}/// 构建和执行链帮助类
class ChainHelper {static Builder builder() {return Builder();}
}/// 用于构建链的构建器类。
class Builder {final ChainHandler _chainHandler = ChainHandler();/// 将拦截器添加到链中。////// 如果提供了 [index],则在指定的索引处添加拦截器。/// 否则,将拦截器添加到链的末尾。Builder addChain(ChainInterceptor interceptor, {int? index}) {_chainHandler.addChain(interceptor, index: index);return this;}/// 设置链的状态监听器。Builder setChainStatusListener(ChainStatusListener chainStatusListener) {_chainHandler.setChainStatusListener(chainStatusListener);return this;}/// 获取 [ChainManager] 实例。ChainHandler get chainHandler => _chainHandler;/// 执行链。void execute() {_chainHandler.proceed();}
}/// 链管理类
class ChainHandler implements Chain {final _chains = <ChainInterceptor>[];int _index = 0;ChainStatusListener? _statusListener;/// 设置链的状态监听器。void setChainStatusListener(ChainStatusListener chainStatusListener) {_statusListener = chainStatusListener;}/// 将拦截器添加到链中。////// 如果提供了 [index],则在指定的索引处添加拦截器。/// 否则,将拦截器添加到链的末尾。@overridevoid addChain(ChainInterceptor interceptor, {int? index}) {if (index != null) {_chains.insert(index, interceptor);} else {_chains.add(interceptor);}}/// 获取链中拦截器的数量。int getChainCount() => _chains.length;/// 当前索引int get currentIndex => _index;/// 执行链。////// 通知 [ChainStatusListener] 链状态的变化。/// 如果链已经执行完毕,则清空链。@overridevoid proceed() {bool isChainEnd = _index >= _chains.length;_statusListener?.onStatusChange(isChainEnd);if (isChainEnd) {clear();return;}_chains[_index++].intercept(this);}/// 清空链void clear() {_chains.clear();_index = 0;}
}

使用

  • 定义多个弹出框
/// 源码:https://github.com/yixiaolunhui/flutter_xy
///第1个弹窗
class OneDialog implements ChainInterceptor {@overridevoid intercept(ChainHandler chain) {showDialog(builder: (BuildContext context) {return AlertDialog(title: const Text('第1个弹出框'),content: const Text('这个是一个弹出框的内容文案'),actions: [TextButton(onPressed: () {Navigator.pop(context);chain.proceed();},child: const Text('取消'),),TextButton(onPressed: () {Navigator.pop(context);chain.proceed();},child: const Text('确认'),),],);},context: App.get().context,);}
}///第2个弹窗
class TwoDialog implements ChainInterceptor {@overridevoid intercept(ChainHandler chain) {showDialog(context: App.get().context,builder: (BuildContext context) {return AlertDialog(title: const Text('第2个弹出框'),content: const Text('这个是一个弹出框的内容文案'),actions: [TextButton(onPressed: () {Navigator.pop(context);chain.proceed();},child: const Text('取消'),),TextButton(onPressed: () {Navigator.pop(context);//这里模拟插入新的弹出框,一般场景是点击按钮后,请求网络然后需要弹出新的弹出框chain.addChain(OtherDialog(), index: chain.currentIndex);chain.proceed();},child: const Text('添加其他弹出框'),),],);},);}
}///第3个弹窗
class ThreeDialog implements ChainInterceptor {@overridevoid intercept(ChainHandler chain) {showDialog(context: App.get().context,builder: (BuildContext context) {return AlertDialog(title: const Text('第3个弹出框'),content: const Text('这个是一个弹出框的内容文案'),actions: [TextButton(onPressed: () {Navigator.pop(context);chain.proceed();},child: const Text('取消'),),TextButton(onPressed: () {Navigator.pop(context);chain.addChain(OtherDialog(), index: chain.currentIndex);chain.proceed();},child: const Text('添加其他弹出框'),),],);},);}
}///第4个弹窗
class FourDialog implements ChainInterceptor {@overridevoid intercept(ChainHandler chain) {showDialog(builder: (BuildContext context) {return AlertDialog(title: const Text('第4个弹出框'),content: const Text('这个是一个弹出框的内容文案'),actions: [TextButton(onPressed: () {Navigator.pop(context);chain.proceed();},child: const Text('取消'),),TextButton(onPressed: () {Navigator.pop(context);chain.proceed();},child: const Text('确认'),),],);},context: App.get().context,);}
}///其他弹窗(用于案例中插入用)
class OtherDialog implements ChainInterceptor {@overridevoid intercept(ChainHandler chain) {showDialog(context: App.get().context,builder: (BuildContext context) {return AlertDialog(title: const Text('其他弹出框'),content: const Text('这个是一个弹出框的内容文案'),actions: [TextButton(onPressed: () {Navigator.pop(context);chain.proceed();},child: const Text('取消'),),TextButton(onPressed: () {Navigator.pop(context);chain.proceed();},child: const Text('确认'),),],);},);}
}
  • 如何使用
class ChainDialogPage extends StatefulWidget {const ChainDialogPage({super.key});@overrideState<ChainDialogPage> createState() => _ChainDialogPageState();
}class _ChainDialogPageState extends State<ChainDialogPage> {var chainHelper = ChainHelper.builder();@overridevoid initState() {super.initState();}//显示对话框void showDialogs() {chainHelper.addChain(OneDialog());chainHelper.addChain(TwoDialog());chainHelper.addChain(ThreeDialog());chainHelper.addChain(FourDialog());chainHelper.execute();}@overrideWidget build(BuildContext context) {return Scaffold(appBar: XYAppBar(title: "Flutter弹框链",onBack: () {Navigator.pop(context);},),body: SafeArea(child: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [ElevatedButton(onPressed: () {showDialogs();},child: const Text("启动弹框链"),),],),),),);}
}

运行后效果

详情:github.com/yixiaolunhui/flutter_xy

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据Scala教程从入门到精通第五篇:Scala环境搭建

一&#xff1a;安装步骤 1&#xff1a;scala安装 1&#xff1a;首先确保 JDK1.8 安装成功: 2&#xff1a;下载对应的 Scala 安装文件 scala-2.12.11.zip 3&#xff1a;解压 scala-2.12.11.zip 4&#xff1a;配置 Scala 的环境变量 在Windows上安装Scala_windows安装scala…

(delphi11最新学习资料) Object Pascal 学习笔记---第11章第1节 (Weak 和 Unsafe 类型接口引用)

11.1.4 Weak 和 Unsafe 类型接口引用 ​ 从 Delphi 10.1 Berlin 开始&#xff0c;Object Pascal 语言对接口引用的管理进行了优化。实际上&#xff0c;Object Pascal 语言提供了不同类型的引用&#xff1a; 常规引用在分配和释放时分别递增和递减对象引用计数&#xff0c;最终…

控制元素隐藏

一、隐藏元素 在CSS中&#xff0c;有几种方法可以隐藏元素&#xff0c;每种方法都有其特定的用例和效果。以下是一些常用的CSS属性和技巧&#xff0c;用于隐藏元素&#xff1a; display: none; 这是最常用的隐藏元素的方法。它会将元素完全从文档流中移除&#xff0c;元素不会…

docker搭建代码审计平台sonarqube

docker搭建代码审计平台sonarqube 一、代码审计关注的质量指标二、静态分析技术分类三、sonarqube流程四、快速搭建sonarqube五、sonarqube scanner的安装和使用 一、代码审计关注的质量指标 代码坏味道 代码规范技术债评估 bug和漏洞代码重复度单测与集成 测试用例数量覆盖率…

node报错——解决Error: error:0308010C:digital envelope routines::unsupported——亲测可用

今天在打包vue2项目时&#xff0c;遇到一个报错&#xff1a; 最关键的代码如下&#xff1a; Error: error:0308010C:digital envelope routines::unsupportedat new Hash (node:internal/crypto/hash:80:19)百度后发现是node版本的问题。 在昨天我确实操作了一下node&…

Ansible——Playbook剧本

目录 一、Playbook概述 1.Playbook定义 2.Playbook组成 3.Playbook配置文件详解 4.运行Playbook 4.1Ansible-Playbook相关命令 4.2运行Playbook启动httpd服务 4.3变量的定义和引用 4.4指定远程主机sudo切换用户 4.5When——条件判断 4.6迭代 4.6.1创建文件夹 4.6.2…

[Linux][网络][TCP][四][流量控制][拥塞控制]详细讲解

目录 1.流量控制2.拥塞控制0.为什么要有拥塞控制&#xff0c;不是有流量控制么&#xff1f;1.什么是拥塞窗口&#xff1f;和发送窗口有什么关系呢&#xff1f;2.怎么知道当前网络是否出现了拥塞呢&#xff1f;3.拥塞控制有哪些算法&#xff1f;4.慢启动5.拥塞避免6.拥塞发生7.快…

劝退计算机?CS再过几年会没落!?

事实上&#xff0c;未来计算机不仅不会没落&#xff0c;国家还会大力发展 只不过大家认为的计算机就是什么Java web&#xff0c;真正的计算机行业是老美那样的&#xff0c;涉及到方方面面&#xff0c;比如&#xff1a; web&#xff0c;图形学&#xff0c;Linux系统开发&#…

pip 安装插件加速技巧: 修改为国内源

在国内&#xff0c;用 pip 安装 python 依赖包的时候&#xff0c;总是会遇到 Timeout 或者下载太慢的问题。 这是因为 pip 源在国外&#xff0c;解决方法就是把 pip 源改成国内的&#xff0c;就可以实现 pip install 加速。 1. 国内有哪些 pip 源&#xff1f; 国内有几个名气比…

2024DCIC海上风电出力预测Top方案 + 光伏发电出力高分方案学习记录

海上风电出力预测 赛题数据 海上风电出力预测的用电数据分为训练组和测试组两大类&#xff0c;主要包括风电场基本信息、气象变量数据和实际功率数据三个部分。风电场基本信息主要是各风电场的装机容量等信息&#xff1b;气象变量数据是从2022年1月到2024年1月份&#xff0c;…

Skywalking数据持久化与自定义链路追踪

学习本篇文章之前首先要了解一下Sky walking的基础知识 分布式链路追踪工具Skywalking详解 一&#xff0c;Sky walking数据持久化 Sky walking提供了es&#xff0c;MySQL等数据持久化方案&#xff0c;默认使用h2基于内存的数据库&#xff0c;重启之后数据即会丢失。 在实际工…

ORM框架在Java、Python、PHP中与MySQL的交互及优缺点比较

在现代软件开发中&#xff0c;对象关系映射&#xff08;Object-Relational Mapping&#xff0c;简称ORM&#xff09;框架已经成为连接应用程序与数据库的重要工具。ORM框架通过提供一组方法&#xff0c;将数据库中的表与应用程序中的对象进行映射&#xff0c;从而简化了数据访问…

博客园商业化之路-众包平台:从第一单看基于「开发任务」的定位

虽然我们一再强调我们做的是「开发任务」众包平台&#xff0c;还是被不少人误解为「项目」众包平台&#xff0c;正好我们遇到的第一单就是一个典型案例&#xff0c;简单发篇博文分享一下。 4月29日我们开始召集众包平台的早期合作开发者&#xff0c;先以手动挡方式&#xff08…

微信小程序下载文件详解

在微信小程序中&#xff0c;下载文件通常涉及使用 wx.downloadFile API。这个 API 可以将网络资源下载到本地临时文件路径&#xff0c;然后你可以使用 wx.saveFile 将临时文件保存到本地持久存储位置。下面是一个下载文件的详细过程&#xff1a; 使用 wx.downloadFile 下载文件…

【Git】Git学习-16:git merge,且解决合并冲突

学习视频链接&#xff1a; 【GeekHour】一小时Git教程_哔哩哔哩_bilibili​编辑https://www.bilibili.com/video/BV1HM411377j/?vd_source95dda35ac10d1ae6785cc7006f365780 1 创建分支dev&#xff0c;并用merge合并master分支&#xff0c;使dev分支合并上master分支中内容为…

【学习笔记】HarmonyOS 4.0 鸿蒙Next 应用开发--安装开发环境

开发前的准备 首先先到官网去下载Devco Studio 这个开发工具&#xff0c;https://developer.harmonyos.com/cn/develop/deveco-studio/#download 提供了WIndows和Mac的开发环境&#xff0c;我自己是Windows的开发环境。 所以下载之后直接点击exe进行安装即可。 如果之前安装过…

C#WPF控件ViewBox详解

本文详解C#WPF控件ViewBox。 目录 定义 常用的属性 事件 实例 定义 ViewBox控件是一个用于缩放和调整其子元素大小的容器控件。它可以根据可用空间自动调整子元素的大小,以使其适应ViewBox的边界。这使得在不同尺寸的窗口或布局中保持元素的比例和缩放变得更加容易。

vue如何进行如何进行移动端的响应式布局

在Vue中进行移动端的响应式布局&#xff0c;通常涉及使用CSS媒体查询、灵活的盒模型布局、以及可能的第三方库或框架&#xff0c;如Vue UI库。下面是一个简单的Vue组件示例&#xff0c;展示了如何构建移动端的响应式布局&#xff1a; 首先&#xff0c;确保你有一个Vue项目。如…

Eplan带你做项目——如何实现项目的交付

前言 Eplan作为一款专业的电气工程设计软件&#xff0c;不仅在设计阶段为电气工程师提供了强大的绘图、计算、仿真等功能&#xff0c;还具备丰富的数据管理与交换能力&#xff0c;能够便捷、准确地导出软件设计、生产制造所需的数据&#xff0c;实现电气设计与软件设计、生产制…

Moby简介:openEuler 中的开源docker引擎

Moby 是一个开源的容器化引擎&#xff0c;它提供了创建和管理容器所需的核心功能。在 openEuler 系统中&#xff0c;Moby 作为容器技术的实现之一&#xff0c;它允许用户利用容器化技术来部署、运行和移植应用程序。 Moby 的功能和作用&#xff1a; 1. **容器创建**&#xff…