Flutter 小技巧之 OverlayPortal 实现自限性和可共享的页面图层

大家对于 Overlay 可能不会陌生,那么 OverlayPortal 呢?

在 Flutter 中可以通过向 MaterialApp 下的 Overlay 添加“图层”,来实现比如「增加一个全局悬浮控件」或者「页面指引」之类的实现,这是因为 Overlay 在 Flutter 里类似于一个“图层管理器”,它的内部有一个 _Theater(剧院),默认情况下每个「Route 页面」都是通过 OverlayEntry 被加入到“剧院”里去展示。

例如我们常用的 Navigator 其实就是使用了 Overlay 来承载「路由页面」,每个打开的 Route 默认情况下是向 Overlay 插入 OverlayEntry 来增加“图层”,每个 OverlayEntry 在层级上互相独立,这也是买个 Route 互不影响的原因之一。

感兴趣可以看以前的老文章 《Flutter 的导航解密和性能提升》

也就是说,之前我们一般都是通过 OverlayOverlayEntry 来实现增加新图层的需要,那这次提到的 OverlayPortal 又是什么东西?

事实上 OverlayPortal 也是用来向 Overlay 添加图层的实现,但是它和 OverlayEntry 又有很大不一样,最大的不一样在于它的「可共享页面状态」和「具有页面自限性」

前面我们聊到,因为每个 OverlayEntryOverlay 下都是平级且“互不影响”,所以当你在页面 A 内唤起一个 新的 OverlayEntry B , 那么 A 是没办法直接通过 InheritedWidget 共享各种状态,因为新的 OverlayEntry B 不属于页面 A ,而是互为平级的 OverlayEntry ,例如下方 Text('Hello') 无法共享“隔壁”的 Theme

那么 OverlayPortal 就不一样了,它可以做到「状态和父级相关联」,但是「在图层结构上又相互独立」,从而实现更简单的页面内「屏幕图层」操作,比如页面内的浮动窗口,弹出框等。

Flutter 内置的 OverlayPortal 是受到 flutter_portal 的启发,在去年的 flutter/flutter#105335 中合并 。

举个例子,如下代码所示:

  • 在页面内定义了一个 DefaultTextStyle 用于往下共享修改后的全局文本样式 fontSize: 20
  • 增加一个 OverlayPortal 并绑定 OverlayPortalController 用于控制 show 或者 hide
  • overlayChildBuilder 里返回一个「提示文本」,「提示文本」可以随机出现在屏幕任何位置
  • 添加 child 显示一个正常的 Text 文本
  • 点击 onPressed 通过 _tooltipController.toggle 显示和隐藏「提示文本」
class ClickableTooltipWidgetState extends State<ClickableTooltipWidget> {final OverlayPortalController _tooltipController = OverlayPortalController();final Random random = Random();Widget build(BuildContext context) {return Container(height: 50,width: 300,decoration: BoxDecoration(color: Colors.blue, borderRadius: BorderRadius.circular(10)),child: TextButton(///点击 OverlayPortalController 实现展示和隐藏onPressed: _tooltipController.toggle,child: DefaultTextStyle( 共享了 DefaultTextStyle 的 fontSize: 20 修改style: DefaultTextStyle.of(context).style.copyWith(fontSize: 20),/// 使用了 OverlayPortal child: OverlayPortal(controller: _tooltipController,/// 通过 overlayChildBuilder 增加图层overlayChildBuilder: (BuildContext context) {return Positioned(right: random.nextInt(200).toDouble(),bottom: random.nextInt(500).toDouble(),child: const ColoredBox(color: Colors.amberAccent,child: Text('Text Everyone Wants to See'),),);},/// 页面内的 child child: const Text('Press to show/hide'),),),),);}
}

可以看到,在点击屏幕中间的按键之后, overlayChildBuilder 内的「提示文本」可以随意在屏幕任意位置出现和隐藏,也就是:

  • 「提示文本」的布局和绘制不受页面 Container 的布局约束,因为它是被加入到 Overlay 到“独立图层”
  • 「提示文本」的样式继承了 DefaultTextStyle 往下共享的样式,所以它的状况又可以和当前页面渲染树同步。

再举个例子,比如在 OverlayPortal 显示 「提示文本」 文本的时候,我们关掉页面,此时因为 OverlayPortal 和页面是相关联的,所以它会被“直接销毁”,这也是它页面自限性的体现:

那到这里,有没有觉得「很神奇」, OverlayPortal 是如何做到状态和父级相关联,但是在图层结构上又相互独立的呢?

简单来说就是这样一张图,它通过 _RenderLayoutSurrogateProxyBox 存在页面 tree 里面,但是又通过 _RenderDeferredLayoutBox “布局和绘制” 在全局的 OverLay 里:

就是一个 OverlayPortal 内部都有这两个实现对象:

  • 每个页面的 OverlayEntry 都有持有一个 LinkedList<_OverlayEntryLocation> _sortedTheaterSiblings 的列表

  • 每个有 OverlayPortal 显示就会有一个 _OverlayEntryLocation ,它相当于是一个 slotOverlayPortal#overlayChildBuilder 相当于是向当前页面的 OverlayEntry_sortedTheaterSiblings 添加了一个 _OverlayEntryLocation

  • 最后这个 slot 会通过如 _theater._addDeferredChild(child); 触发布局更新

再稍微捋一捋,大概就是: OverlayPortal#overlayChildBuilder 的最终布局和绘制,其实都是通过 Overlay 的内部统一的 _Theater(剧院)完成,所以它在这个层面上其实和 OverlayEntry 相似,只是 Overlay 是通过 slot 等方式 “间接” 参与,本身它还是存在于页面的 tree 下面

而从层级上来说:

  • 在 Overlay 中, OverlayPortal 通常位于最靠近它的 OverlayEntry(一般就是页面 Route) 之后,并在下一个 OverlayEntry 之前,所以它可以存在于当前页面任意位置,又不会遮挡到下一个页面

  • OverlayEntry 具有多个关联的 OverlayPortal 时,它们之间的绘制顺序是调用 verlayPortalController.show 的顺序

所以可以看到, OverlayPortal 主要是为我们补充了「页面内全局图层」的场景,因为它可以做到状态和父级相关联,但是在图层结构上又相互独立 ,适当使用 OverlayPortal 替代 OverlayEntry ,可以让我们更灵活搭配各种页面内的渲染场景,比如图层,指引,甚至通过局部图层来实现切换动画:

当然,这个动画怎么实现,那就是另外一个故事了: 《Shader 实现酷炫的粒子动画》

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

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

相关文章

FlinkPipelineComposer 详解

FlinkPipelineComposer 详解 原文 背景 在flink-cdc 3.0中引入了pipeline机制&#xff0c;提供了除Datastream api/flink sql以外的一种方式定义flink 任务 通过提供一个yaml文件&#xff0c;描述source sink transform等主要信息 由FlinkPipelineComposer解析&#xff0c…

AutoDL远程连接技巧

写在前面 本次只是个人经验分享 面是我随便复制的 登录指令&#xff1a;ssh -p 38292 rootconnect.c1.seetacloud.com 登录密码&#xff1a;YBjlgzbZNou 在下面图片中&#xff1a;名称可以随便取&#xff1a; 协议一般选择SSH&#xff0c;主机名称就是后面的&#xff1b;用我的…

FPGA学习(10)-数码管

前3节视频目的是实现显示0~F的数码管仿真&#xff0c;后3节是用驱动芯片驱动数码管。 目录 1.数码管显示原理 2.代码过程 2.1仿真结果 3.串行移位寄存器原理 3.1原理 ​编辑 3.2 数据手册 3.3 先行设计思路 4.程序 4.1确定SRCLK的频率 4.2序列计数器 4.3 不同coun…

k8s 1.28.2 集群部署 docker registry 接入 MinIO 存储

文章目录 [toc]docker registry 部署生成 htpasswd 文件生成 secret 文件 生成 registry 配置文件创建 service创建 statefulset创建 ingress验证 docker registry docker registry 监控docker registry ui docker registry dockerfile docker registry 配置文件 S3 storage dr…

软件工程笔记二—— 软件生存期模型

目录 瀑布模型 瀑布模型的特点 阶段间具有顺序性和依赖性。 推迟实现的观点 质量保证的观点 瀑布模型的优点 瀑布模型的缺点 快速原型模型 快速原型模型的优点 快速原型模型的缺点 增量模型 增量模型的优点 增量构件开发 螺旋模型 完整的螺旋模型&#xff08;顺…

万字长文解读深度学习——生成对抗网络GAN

&#x1f33a;历史文章列表&#x1f33a; 深度学习——优化算法、激活函数、归一化、正则化深度学习——权重初始化、评估指标、梯度消失和梯度爆炸深度学习——前向传播与反向传播、神经网络&#xff08;前馈神经网络与反馈神经网络&#xff09;、常见算法概要汇总万字长文解读…

【MYSQL】数据库日志 (了解即可)

一、错误日志 可以通过 tail查看文件的日志的&#xff0c;如果发生错误&#xff0c;就会在日志里出现问题。 二、二进制日志&#xff08;binlog&#xff09; BINLOG记录了insert delete update 以及 alter create drop 等语句。作用是灾难时的数据恢复&#xff0c;还有就是主…

整理iPhone空间:iphone怎么删除相簿

随着时间的积累&#xff0c;我们的iPhone中不仅会堆积大量照片&#xff0c;还可能会有多个不再需要的相簿。这些相簿不仅占用存储空间&#xff0c;还可能使相册应用变得杂乱无章。本文将探讨iphone怎么删除相簿&#xff0c;并介绍精简iPhone相册的技巧&#xff0c;使你的相册管…

ABAP关于PS模块CJ20N中项目物料的屏幕和字段增强CI_RSADD

网上搜关于CJ20N的屏幕增强,基本都是关于项目定义(CI_PROJ)、项目WBS(CI_PRPS)、项目网络活动工序(CI_AFVU)的字段与屏幕增强,几乎没有关于项目物料(CI_RSADD)的字段屏幕增强,我在这里做一个分享。 主要逻辑:实现badi增强,并自建一个函数组后创建屏幕,在badi里面调用…

Kettle配置数据源错误“Driver class ‘org.gjt.mm.mysql.Driver‘ could not be found”解决记录

问题描述 错误提示&#xff1a;“Driver class ‘org.gjt.mm.mysql.Driver’ could not be found, make sure the ‘MySQL’ driver (jar file) is installed.” 原因分析&#xff1a; 根据错误提示是缺少了相关的数据源连接jar包。 解决方案&#xff1a; 安装对应的Mysql…

基于Python 和 pyecharts 制作招聘数据可视化分析大屏

在本教程中&#xff0c;我们将展示如何使用 Python 和 pyecharts 库&#xff0c;通过对招聘数据的分析&#xff0c;制作一个交互式的招聘数据分析大屏。此大屏将通过不同类型的图表&#xff08;如柱状图、饼图、词云图等&#xff09;展示招聘行业、职位要求、薪资分布等信息。 …

人力资源招聘系统的革新之路:从传统到智能的转变

在全球化与数字化交织的今天&#xff0c;企业间的竞争日益激烈&#xff0c;而人才作为企业发展的核心驱动力&#xff0c;其重要性不言而喻。传统的人力资源招聘方式&#xff0c;如依赖纸质简历、人工筛选、面对面面试等&#xff0c;不仅效率低下&#xff0c;且难以精准匹配企业…

UE5 UE4 播放视频没有声音解决

开启AVF插件 在项目设置中&#xff0c;AVF 的调试打开。 在项目设置中,WMF Media 中&#xff0c;allow Non standard Codecs,Low Latency 和 Native Audio Out打开。

sql专题 之 where和join on

文章目录 前言where介绍使用过滤结果集关联两个表 连接外连接内连接自然连接 使用inner join和直接使用where关联两个表的区别总结 前言 从数据库查询数据时&#xff0c;一张表不足以查询到我们想要的数据&#xff0c;更多的时候我们需要联表查询。 联表查询我们一般会使用连接…

如何在CentOS 7上搭建SMB服务

如何在CentOS 7上搭建SMB服务 因项目测试需求&#xff0c;需要自行搭建SMB服务&#xff0c;**SMB&#xff08;Server Message Block&#xff09;**协议是一种常用的文件共享方式&#xff0c;它可以让不同操作系统之间共享文件、打印机等资源。本文将带你一步步搭建一个简单的S…

使用CNN进行验证码识别:深度学习与图像预处理教程

验证码&#xff08;CAPTCHA&#xff09;广泛用于区分人类和自动化程序&#xff08;如机器人&#xff09;&#xff0c;通常由扭曲的字母、数字或符号组成。为了实现验证码的自动识别&#xff0c;深度学习尤其是卷积神经网络&#xff08;CNN&#xff09;非常有效。本文将带你一起…

STM32 51单片机设计半导体制冷片温控设计

目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 1.电路图采用Altium Designer进行设计&#xff1a; 三、实物设计图 四、程序源代码设计 五、获取资料内容 前言 基于STM32与51单片机的半导体制冷片温控设计 前言 随着现代工业、医疗…

ssm114基于SSM框架的网上拍卖系统的设计与实现+vue(论文+源码)_kaic

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff0c;商品拍卖当然也不能排除在外&#xff0c;随着商品拍卖管理的不断成熟&#xff0c;它彻底改变了过去传统的经营管理方式&#xff0c;不仅使商品…

算法每日双题精讲——滑动窗口(长度最小的子数组,无重复字符的最长子串)

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 别再犹豫了&#xff01;快来订阅我们的算法每日双题精讲专栏&#xff0c;一起踏上算法学习的精彩之旅吧&#xff01;&#x1f4aa;…

批量从Excel某一列中找到符合要求的值并提取其对应数据

本文介绍在Excel中&#xff0c;从某一列数据中找到与已知数据对应的字段&#xff0c;并提取这个字段对应数值的方法。 首先&#xff0c;来明确一下我们的需求。现在已知一个Excel数据&#xff0c;假设其中W列包含了上海市全部社区的名称&#xff0c;而其后的Y列则是这些社区对应…