Overlay
/OverlayEntry
- 声明式而非命令式,直观的上下文,以及简易的对齐想要显示浮动覆盖层 - 工具提示、上下文菜单、对话框、气泡等?这个库是对 Flutter 内置 Overlay/OverlayEntry 的增强和替代。
为什么使用 flutter_portal
而不是内置的 Overlay/OverlayEntry/OverlayPortal?
.insert()
等方式进行命令式操作。</sub>shiftToWithinBound
),将其与 portal 而不是父 widget 对齐(alignToPortal
),您甚至可以创建自己的对齐算法(扩展 EnhancedCompositedTransformAnchor
)。<sub>对比:Overlay 似乎没有这种功能。</sub>Context
:覆盖层条目使用其直观的父级作为 context
进行构建。<sub>对比:Overlay 方法使用远处的覆盖层作为其 context
。更新:OverlayPortal(受本包启发)在这方面有所改进。</sub>因此,还具有以下优点:
setState
一样简单,RestorableProperty
可以很好地工作。<sub>对比:使用 Overlay 方法时,当应用程序被操作系统终止时,我们的模态框状态不会被恢复。</sub>Theme
/provider
:由于覆盖层条目具有直观的 context
,它可以访问与显示覆盖层的 widget 相同的 Theme
和不同的 provider
。<sub>对比:Overlay 方法会产生令人困惑的 Theme 和 provider。更新:OverlayPortal(受本包启发)在这方面有所改进。</sub>PortalTarget( // 1. 声明式:只需将 `portalFollower` 作为普通 widget 提供 // 2. 内部具有直观的 BuildContext portalFollower: MyAwesomeOverlayWidget(), // 3. 可以随意将"follower"相对于"child"对齐 anchor: Aligned.center, child: MyChildWidget(), )
要从 0.x 迁移到 1.x,请参阅 readme 的最后一节。
查看 examples
文件夹以了解如何使用 flutter_portal 的示例:
部分截图:
上下文菜单 | 引导视图 |
---|---|
<img width="300px" src="https://yellow-cdn.veclightyear.com/835a84d5/01194457-be4f-4ee2-aa68-a47fd0dc6cad.png"> | <img src="https://yellow-cdn.veclightyear.com/835a84d5/49c56226-c731-4092-b81f-19f5d48d85af.gif" alt="Discovery example" style="300px"> |
flutter pub add flutter_portal
。MaterialApp
之上。每个应用程序只需要一个 Portal。在这个例子中,我们将看到如何使用 flutter_portal 在点击 RaisedButton
后显示菜单。
在做任何事情之前,您必须在 widget 树中插入 Portal widget。follower widget 将表现得好像它们是作为这个 widget 的子项插入的。
您可以将这个 Portal 放在 MaterialApp
之上或靠近路由的根部:
Portal( child: MaterialApp(...) )
首先,我们需要创建一个渲染 RaisedButton
的 StatefulWidget
:
<p align="center"> <img src="https://yellow-cdn.veclightyear.com/835a84d5/3519d458-852b-4660-887b-ce6168abb246.png" alt="image" width="200px"> </p>class MenuExample extends StatefulWidget { _MenuExampleState createState() => _MenuExampleState(); } class _MenuExampleState extends State<MenuExample> { Widget build(BuildContext context) { return Scaffold( body: Center( child: RaisedButton( onPressed: () {}, child: Text('show menu'), ), ), ); } }
然后,我们需要在 widget 树中插入 PortalTarget。
我们希望上下文菜单紧靠 RaisedButton
渲染。
因此,我们的 PortalTarget 应该是 RaisedButton
的父级,如下所示:
child: PortalTarget( visible: // TODO anchor: // TODO portalFollower: // TODO child: RaisedButton(...), ),
我们可以将菜单传递给 PortalTarget:
<p align="center"> <img width="200px" src="https://yellow-cdn.veclightyear.com/835a84d5/8c1938bb-bb97-4dca-a192-30a49822b198.png"> </p>PortalTarget( visible: true, anchor: Filled(), portalFollower: Material( elevation: 8, child: IntrinsicWidth( child: Column( mainAxisSize: MainAxisSize.min, children: [ ListTile(title: Text('option 1')), ListTile(title: Text('option 2')), ], ), ), ), child: RaisedButton(...), )
在这个阶段,您可能会注意到两件事:
anchor
是 Filled
)visible
是 true)让我们先解决全屏问题,并更改我们的代码,使菜单在 RaisedButton
的右侧渲染。
要将菜单对齐到按钮周围,我们可以更改 anchor
参数:
<p align="center"> <img width="200px" src="https://yellow-cdn.veclightyear.com/835a84d5/09125d1b-b7b3-4291-a818-6778db9088dc.png"> </p> 这段代码的意思是,将菜单的左上角与 `RaisedButton` 的右上角对齐。这样,我们的菜单就不再是全屏的,而是位于按钮的右侧。PortalTarget( visible: true, anchor: const Aligned( follower: Alignment.topLeft, target: Alignment.topRight, ), portalFollower: Material(...), child: RaisedButton(...), )
最后,我们可以更新代码,使菜单只在点击按钮时显示。
为此,我们需要在 StatefulWidget
中声明一个新的布尔值,表示菜单是否打开:
class _MenuExampleState extends State<MenuExample> { bool isMenuOpen = false; ... }
然后,我们将这个 isMenuOpen
变量传递给 PortalEntry:
PortalTarget( visible: isMenuOpen, ... )
接着,在 RaisedButton
的 onPressed
回调中,我们可以更新这个 isMenuOpen
变量:
RaisedButton( onPressed: () { setState(() { isMenuOpen = true; }); }, child: Text('show menu'), ),
最后一步是在用户点击菜单外部时关闭菜单。
这可以通过结合使用第二个 PortalEntry 和 [GestureDetector] 来实现,如下所示:
PortalTarget( visible: isMenuOpen, portalFollower: GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { setState(() { isMenuOpen = false; }); }, ), ... ),
在使用flutter_portal
时,有几个概念需要充分理解。特别是如果你想支持自定义用例,这在提供的抽象API中是很容易实现的。
以下将高层次地解释你需要理解的每个抽象概念。你会在类名(如Portal
部件或PortalTarget
部件)以及参数名中找到它们。
Portal(或者如果你只有一个的话,就是the portal)是用于进行所有portal工作的空间。在底层,这意味着你有一个部件,允许其子树放置相互连接的目标和跟随者。
Portal还定义了可供任何跟随者在屏幕上渲染的可用区域(矩形边界)。
具体来说,你可能会将整个MaterialApp
包裹在一个单独的Portal
部件中,这意味着你可以使用应用的整个区域来渲染附加到Portal
部件子级的目标的跟随者。
目标是portal内可以被跟随者跟随的任何位置。这允许你将任何你想要叠加的内容附加到UI中的特定位置,无论它如何动态移动。
在底层,这意味着你将UI中你想要跟随的部分包裹在一个PortalTarget
部件中并进行配置。
想象你想在应用中当头像被悬停时显示工具提示。在这种情况下,头像将是portal的目标,可用于锚定叠加的工具提示。
另一个例子是下拉菜 单。显示当前选择的部件是目标,当点击它时,下拉选项将通过portal作为跟随者叠加显示。
跟随者只能与目标结合使用。你可以将其用于任何你想要叠加在UI顶部的内容,附加到目标上。
具体来说,这意味着你可以为每个PortalTarget
传递一个follower
,当你指定时,它将显示在UI上方的portal内。
如果你想使用flutter_portal
显示一个自动完成文本字段,你会想要跟随文本字段来叠加你的自动完成建议。在这种情况下,自动完成建议的部件将是portal的跟随者。
锚点定义了目标和跟随者之间的布局连接。通常,锚点被实现为一个抽象API,提供支持任何你想要的定位所需的所有信息。这意味着锚点可以基于相关portal、目标和跟随者的属性来定义。
默认实现了一些锚点,例如Aligned
或Filled
。
从0.x到1.0版本有一些破坏性变更(主要由#44引入),但可以轻松迁移。以下是示例:
PortalEntry( portalAnchor: Alignment.topLeft, childAnchor: Alignment.topRight, portal: MyAwesomePortalWidget(), child: MyAwesomeChildWidget(), )
变为:
PortalTarget( anchor: const Aligned( follower: Alignment.topLeft, target: Alignment.topRight, ), portalFollower: MyAwesomePortalWidget(), child: MyAwesomeChildWidget(), )
如果你原本使用PortalEntry
时没有设置portalAnchor
/childAnchor
(即使其全屏显示),那么你可以这样写:
PortalTarget( anchor: const Filled(), ... )
所有者
CHANGELOG.md
了解贡献。贡献者
字节跳动发布的AI编程神器IDE
Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。
AI小说写作助手,一站式润色、改写、扩写
蛙蛙写作—国内先进的AI写作平台,涵盖小说、学术、社交媒体等多场景。提供续写、改写、润色等功能,助力创作者高效优化写作流程。界面简洁,功能全面,适合各类写作者提升内容品质和工作效率。
全能AI智能助手,随时解答生活与工作的多样问题
问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。
实时语音翻译/同声传译工具
Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。
一键生成PPT和Word,让学习生活更轻松
讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。
深度推理能力全新升级,全面对标OpenAI o1
科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种 文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。
一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型
Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。
AI助力,做PPT更简单!
咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。
选题、配图、成文,一站式创作,让内容运营更高效
讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。
专业的AI公文写作平台,公文写作神器
AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快 速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。