猫哥课堂 ducafecat.com
开通 VIP 会员, 观看所有视频、附件、猫哥密友、猫哥 VIP 群

Flutter Overlay 你用上了么

Flutter overlay did you use it?

前言

Flutter中的Overlay是一个用于在屏幕上显示浮层的组件。它可以用来在应用程序中创建弹出窗口、提示框、菜单、对话框等等。

Overlay通常用于在用户与应用程序交互时显示临时性的UI元素,例如:用户点击按钮时显示下拉菜单、用户长按屏幕时显示上下文菜单、显示警告或错误消息等等。

Overlay通常包含一个Stack布局,每个浮层都是一个Positioned widget,可以添加到Stack中。这样,可以将多个浮层叠加在一起,并控制它们的层次关系。

Flutter中的Overlay可以让开发者轻松创建复杂的UI,同时还可以保持应用程序的性能和响应度。

本文中提供的代码示例演示了如何在Flutter中使用Overlay制作工作覆盖层。Overlay包括两个基本组件:OverlayState和OverlayEntry。OverlayState管理所有OverlayEntry,OverlayEntry定义覆盖层中的内容。在示例中,OverlayEntry包含一个带有文本和颜色的容器,可以在屏幕上显示。这些条目可以通过OverlayState的insert和remove方法添加和删除。

原文 https://ducafecat.com/blog/flutter-overlay-did-you-use-it

image-20230518102503338

视频

https://www.bilibili.com/video/BV1qX4y1C7rb/

代码

https://github.com/ducafecat/flutter_develop_tips/tree/main/flutter_application_overlay

参考

https://api.flutter.dev/flutter/widgets/Overlay-class.html

https://api.flutter.dev/flutter/widgets/OverlayEntry-class.html

OverlayEntry

Overlay 通过将独立的子窗口小部件插入到重叠的堆栈中,使它们在其他窗口小部件之上“浮动”可视元素。覆盖允许每个小部件使用 OverlayEntry 对象管理它们在覆盖中的参与。

构造函数

OverlayEntry({ required this.builder, bool opaque = false, bool maintainState = false, })
  • builder:此属性用于此条目,并将在条目位置的覆盖中包含此构建器构建的小部件。

  • opaque:此属性用于获取bool值,该值决定此条目是否阻止整个覆盖。如果条目声明为不透明,则为了提高效率,除非它们具有maintainState设置,否则覆盖将跳过在该条目下面构建条目。
  • maintainState:如果您需要在OverlayEntry中使用有状态的小部件,那么您需要将maintainState设置为true,以便小部件可以保持其状态并接收生命周期方法。如果您只是在OverlayEntry中显示一个静态小部件,则可以将maintainState设置为false,以便小部件可以释放内存和资源,不会对性能产生过多影响。

OverlayEntry方法

只有一个OverlayEntry的方法

  • remove:此方法用于从覆盖层中删除此条目

OverlayState

Overlay的当前状态用于将OverlayEntries插入覆盖层中。

OverlayState方法

  • debugIsVisible:此方法用于检查给定的OverlayEntry是否可见,并返回布尔值。
  • insert:此方法用于将给定的OverlayEntry插入覆盖层中。
  • insertAll:此方法用于获取OverlayEntries的List,并将所有条目插入覆盖层中。您还可以指定上述和下述属性以说明要插入条目的顺序。
  • rearrange:它可以重新排列当前在屏幕上叠加的所有小部件。具体来说,rearrange方法会将最后添加的OverlayEntry小部件移动到最上面,并将其他小部件移动到下面。这可以用于确保最新的OverlayEntry始终位于最上面,并且可以接收用户的触摸事件等。

步骤

第一步:成员变量

/// overlay 状态 OverlayState? overlayState; /// overlay 层集合 List<OverlayEntry> entriesList = [];
void initState() { super.initState(); // 获取 overlay 状态 overlayState = Overlay.of(context); }
void dispose() { // 销毁 overlayState?.dispose(); super.dispose(); }

第二步:随机层显示

// 随机位置显示层 void showRandomOverlay(BuildContext context) { // 随机颜色 final bgColor = Color.fromARGB( 255, 1 + Random().nextInt(254), 1 + Random().nextInt(254), 1 + Random().nextInt(254), ); // 屏幕宽度 final screenWidth = MediaQuery.of(context).size.width; // 随机屏幕高度 final randomHeight = MediaQuery.of(context).size.height * Random().nextDouble(); OverlayEntry? overlayEntry; overlayEntry = OverlayEntry(builder: (context) { return Positioned( // 指定位置 left: 0, top: randomHeight, child: GestureDetector( // 点击删除 onTap: () { overlayEntry?.remove(); entriesList.remove(overlayEntry); }, // 背景随机色 child: Container( width: screenWidth, height: 100, color: bgColor, child: Center( // 提示文字 child: Text( "这是一个 overlay ${Random().nextInt(100)} 层, 点击关闭", style: const TextStyle( color: Colors.white, fontSize: 20, decoration: TextDecoration.none, ), ), ), ), ), ); }); overlayState?.insert(overlayEntry); entriesList.add(overlayEntry); }

第三步:控制按钮

// 控制按钮 Widget _buildBtns() { return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ // 随机新增 ElevatedButton( onPressed: () => showRandomOverlay(context), child: const Text("随机新增"), ), // 关闭所有 ElevatedButton( onPressed: () { for (final entry in entriesList) { entry.remove(); } entriesList = []; }, child: const Text("关闭所有"), ), // 随机排序 ElevatedButton( onPressed: () { // 从屏幕上移除 for (final entry in entriesList) { entry.remove(); } // 使用Random类创建随机数生成器 Random random = Random(); // 使用List的sublist()方法创建一个新列表 List<OverlayEntry> shuffledEntries = entriesList.sublist(0); // 调用List的shuffle()方法,传入一个随机数生成器 shuffledEntries.shuffle(random); // 插入界面 overlayState?.insertAll(shuffledEntries); }, child: const Text("随机排序"), ), ], ); }

最后:主视图显示

// 主视图 Widget _mainView() { return Padding( padding: const EdgeInsets.only(top: 100), child: Align( alignment: Alignment.topCenter, child: _buildBtns(), ), ); }
Widget build(BuildContext context) { return Scaffold( body: _mainView(), ); }

完整代码

lib/overlay_view.dart

import 'dart:math'; import 'package:flutter/material.dart'; class OverlayUsePage extends StatefulWidget { const OverlayUsePage({super.key}); State<OverlayUsePage> createState() => _OverlayUsePageState(); } class _OverlayUsePageState extends State<OverlayUsePage> { /// overlay 状态 OverlayState? overlayState; /// overlay 层集合 List<OverlayEntry> entriesList = []; // 随机位置显示层 void showRandomOverlay(BuildContext context) { // 随机颜色 final bgColor = Color.fromARGB( 255, 1 + Random().nextInt(254), 1 + Random().nextInt(254), 1 + Random().nextInt(254), ); // 屏幕宽度 final screenWidth = MediaQuery.of(context).size.width; // 随机屏幕高度 final randomHeight = MediaQuery.of(context).size.height * Random().nextDouble(); OverlayEntry? overlayEntry; overlayEntry = OverlayEntry(builder: (context) { return Positioned( // 指定位置 left: 0, top: randomHeight, child: GestureDetector( // 点击删除 onTap: () { overlayEntry?.remove(); entriesList.remove(overlayEntry); }, // 背景随机色 child: Container( width: screenWidth, height: 100, color: bgColor, child: Center( // 提示文字 child: Text( "这是一个 overlay ${Random().nextInt(100)} 层, 点击关闭", style: const TextStyle( color: Colors.white, fontSize: 20, decoration: TextDecoration.none, ), ), ), ), ), ); }); overlayState?.insert(overlayEntry); entriesList.add(overlayEntry); } // 控制按钮 Widget _buildBtns() { return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ // 随机新增 ElevatedButton( onPressed: () => showRandomOverlay(context), child: const Text("随机新增"), ), // 关闭所有 ElevatedButton( onPressed: () { for (final entry in entriesList) { entry.remove(); } entriesList = []; }, child: const Text("关闭所有"), ), // 随机排序 ElevatedButton( onPressed: () { // 从屏幕上移除 for (final entry in entriesList) { entry.remove(); } // 使用Random类创建随机数生成器 Random random = Random(); // 使用List的sublist()方法创建一个新列表 List<OverlayEntry> shuffledEntries = entriesList.sublist(0); // 调用List的shuffle()方法,传入一个随机数生成器 shuffledEntries.shuffle(random); // 插入界面 overlayState?.insertAll(shuffledEntries); }, child: const Text("随机排序"), ), ], ); } // 主视图 Widget _mainView() { return Padding( padding: const EdgeInsets.only(top: 100), child: Align( alignment: Alignment.topCenter, child: _buildBtns(), ), ); } void initState() { super.initState(); // 获取 overlay 状态 overlayState = Overlay.of(context); } void dispose() { // 销毁 overlayState?.dispose(); super.dispose(); } Widget build(BuildContext context) { return Scaffold( body: _mainView(), ); } }

小结

本文提供了一个很好的介绍Flutter Overlay的概念和使用方法。无论是初学者还是有经验的开发人员,都可以从本文中获得新的知识和见解。如果你想在你的Flutter项目中实现工作覆盖层,本文是一个很好的起点。


© 猫哥 ducafecat.com

end


Copyright 2024 ducafecat. All rights reserved.
微信: ducafecat, line: ducafecat,京ICP备2021009050号-3