HarmonyOS鸿蒙开发 弹窗及加载中指示器HUD功能实现

HarmonyOS鸿蒙开发 弹窗及加载中指示器HUD功能实现

最近在学习鸿蒙开发过程中,阅读了官方文档,在之前做flutter时候,经常使用overlay,使用OverlayEntry加入到overlayState来做添加悬浮按钮、提示弹窗、加载中指示器、加载失败的toast等功能。那在HarmonyOS鸿蒙开发中也可能有类似的功能需求。

HarmonyOS鸿蒙开发的使用弹窗文档中已经非常详细了
地址:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-use-dialog-V5

一、子窗口window

在弹出的loading指示器中,我们可以使用创建子window的方式,调用window的loadContentByName方法来实现。
实现步骤

效果预览

在这里插入图片描述

  • 1、实现加载中的loading组件,这里定义名字为LoadingHud

在LoadingHud中有LoadingProgress、Text提示文本,Text显示的信息由LocalStorage进行传递
需要传递的数据message,在aboutToAppear进行赋值

@Local message: string = '';aboutToAppear(): void {this.message = LocalStorage.getShared().get("message") ?? "";}

当然在调用window的loadContentByName时候,需要确定加载的主角的routeName,这就需要在LoadingHud组件中使用装饰器来设置

/// 通用的hud,弹出框,或者loading框
@Entry({ routeName: "hudLoading", storage: LocalStorage.getShared() })
@ComponentV2
export struct LoadingHud {... 其他代码
}

LoadingHud的完整代码如下:

/// 通用的hud,弹出框,或者loading框
@Entry({ routeName: "hudLoading", storage: LocalStorage.getShared() })
@ComponentV2
export struct LoadingHud {@Local message: string = '';aboutToAppear(): void {this.message = LocalStorage.getShared().get("message") ?? "";}build() {Column() {Column(){Row() {// 从左往右,1号环形进度条,默认前景色为蓝色渐变,默认strokeWidth进度条宽度为2.0vpLoadingProgress().color($r('app.color.success')).width(40).height(40)// messageText(this.message).fontSize(14).fontColor($r('app.color.dataset_empty_message')).margin({left: 10})}.padding({top: 15,bottom: 15,left: 15,right: 20}).justifyContent(FlexAlign.Center)Button("点击消失").width(100).height(40).fontSize(12).backgroundColor('#ef04792c').margin({top: 10}).onClick(()=> {LoadingHudUtil.dismissLoading();})}.justifyContent(FlexAlign.Center).constraintSize({minWidth: 200,minHeight: 150,}).backgroundColor($r('app.color.white')).borderRadius(10)}.justifyContent(FlexAlign.Center).width('100%').height('100%').backgroundColor('#00000000').hitTestBehavior(HitTestMode.Transparent)}
}
  • 2、创建子Window并显示

在创建LoadingHud后,我们需要创建创建子Window并显示window,显示我们的loadingHUD
创建window的createWindow,这里使用的windowType是window.WindowType.TYPE_DIALOG,也可以换成其他的试试看。

let windowName = "loading";// 创建窗口let subWindow = await window.createWindow({name: windowName,windowType: window.WindowType.TYPE_DIALOG,ctx: ctx,});

设置LocalStorage数据,存储message

//创建存储let storage = new LocalStorage();//存储数据storage.setOrCreate('message',  tip);

调用window的loadContentByName,设置Window的大小及背景颜色,显示Window

await subWindow.loadContentByName('hudLoading', storage);let dp = display.getDefaultDisplaySync();await subWindow.resize(dp.width, dp.height);subWindow.setWindowBackgroundColor('#30000000');await subWindow.showWindow();

显示后Window,在需要消失的时候调用destroyWindow

static async dismissLoading(): Promise<void> {if (LoadingHudUtil.cacheWindow) {await LoadingHudUtil.cacheWindow.destroyWindow();}}

完整的LoadingHudUtil的代码如下

import { display, window } from '@kit.ArkUI';
import { common } from '@kit.AbilityKit';
import('../components/hud/LoadingHud'); // 引入命名路由页面// 自定义弹出窗口
export class LoadingHudUtil {private static cacheWindow: window.Window;static async showLoading(tip: string): Promise<void> {let ctx = getContext() as common.UIAbilityContext;try {let windowName = "loading";// 创建窗口let subWindow = await window.createWindow({name: windowName,windowType: window.WindowType.TYPE_DIALOG,ctx: ctx,});LoadingHudUtil.cacheWindow = subWindow;//创建存储let storage = new LocalStorage();//存储数据storage.setOrCreate('message',  tip);console.log("LoadingHudUtil loadContentByName" + tip);// subWindow.setGestureBackEnabled(false);// subWindow.setDialogBackGestureEnabled(false);// subWindow.setWindowTouchable(true);await subWindow.loadContentByName('hudLoading', storage);let dp = display.getDefaultDisplaySync();await subWindow.resize(dp.width, dp.height);subWindow.setWindowBackgroundColor('#30000000');await subWindow.showWindow();} catch (e) {console.log("LoadingHudUtil showLoading e:" + JSON.stringify(e));}}static async dismissLoading(): Promise<void> {if (LoadingHudUtil.cacheWindow) {await LoadingHudUtil.cacheWindow.destroyWindow();}}
}

二、自定义Dialog

在HarmonyOS鸿蒙开发中,可以使用CustomDialogController来实现自定义的弹窗。

效果预览
在这里插入图片描述

  • 1.自定义弹窗组件CustomAlertDialog

在CustomAlertDialog中实现一个消息提示,并且点击按钮可以关闭dialog
代码如下:

@CustomDialog
export struct CustomAlertDialog {controller?: CustomDialogControllertitle?: stringbuild() {Column() {Column() {// messageText(this.title).fontSize(14).fontColor($r('app.color.dataset_empty_message')).margin({left: 10})Button("点击消失").width(100).height(40).fontSize(12).backgroundColor('#ef04792c').margin({top: 10}).onClick(() => {this.controller?.close();})}.justifyContent(FlexAlign.Center).constraintSize({minWidth: 200,minHeight: 100,}).backgroundColor($r('app.color.white')).borderRadius(10)}.justifyContent(FlexAlign.Center).width('100%').height('100%').backgroundColor(Color.Transparent).hitTestBehavior(HitTestMode.Transparent)}
}
  • 2.使用CustomDialogController来展示弹窗

定义CustomDialogController

// 自定义CustomDialogcustomDialogController: CustomDialogController | null = new CustomDialogController({builder: CustomAlertDialog({title: "温馨提示"}),alignment: DialogAlignment.Center,onWillDismiss: (dismissDialogAction: DismissDialogAction) => {console.info("reason=" + JSON.stringify(dismissDialogAction.reason))console.log("dialog onWillDismiss")if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {dismissDialogAction.dismiss()}if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {dismissDialogAction.dismiss()}},autoCancel: true,customStyle: true,});

在需要展示弹窗的时候调用customDialogController的open方法。

 if (this.customDialogController != null) {this.customDialogController.open()}

当然如果页面消失,尽量在aboutToDisappear中将customDialogController置空

  // 在自定义组件即将销毁时将dialogController置空aboutToDisappear() {this.customDialogController = null // 将dialogController置空}

三、Overlay浮层

在官方文档中有一段描述
浮层(OverlayManager) 用于将自定义的UI内容展示在页面(Page)之上,在Dialog、Popup、Menu、BindSheet、BindContentCover和Toast等组件之下,展示的范围为当前窗口安全区内。可适用于常驻悬浮等场景。

使用OverlayManager来添加、删除、隐藏、显示节点Component

效果预览
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 1.定义CustomOverlayView组件界面

在CustomOverlayView中,我们定义了加载中,加载失败,加载成功的几种类型,用于展示不同的样式
定义OverlayConfig类为展示的界面配置、OverlayScaleImage缩放的icon

export enum OverlayType {loading,success,fail
}export class OverlayConfig {message: string = ""offset: Position = { x: 0, y: -50 }index: number = 0autoDismiss: boolean = true;duration: number = 3000 // 持续时间onCallback?: (index: number) => voidtype: OverlayType = OverlayType.loadingconstructor(message: string) {this.message = message}
}@Builder
export function builderCustomOverlayView(overlayConfig: OverlayConfig) {CustomOverlayView({olConfig: overlayConfig})
}@ComponentV2
struct OverlayScaleImage {@Param @Require src: PixelMap | ResourceStr | DrawableDescriptor;@Param imgWidth: number = 40;@Local imgScale: number = 0.0;build() {Image(this.src).width(this.imgWidth).aspectRatio(1).scale({ x: this.imgScale, y: this.imgScale }).animation({duration: 300, // 时长iterations: 1, // 设置-1表示动画无限循环}).onAppear(() => {// 组件挂载完毕,修改数值触发动画效果this.imgScale = 1.0})}
}@ComponentV2
export struct CustomOverlayView {@Param olConfig: OverlayConfig = new OverlayConfig("");aboutToAppear(): void {setTimeout(() => {console.log("CustomOverlayView aboutToAppear");if (this.olConfig.onCallback != null) {this.olConfig.onCallback(this.olConfig.index);}}, this.olConfig.duration);}build() {Column() {if (OverlayType.loading == this.olConfig.type) {// messageLoadingProgress().color($r('app.color.success')).width(40).height(40)} else if (OverlayType.success == this.olConfig.type) {// messageOverlayScaleImage({src: $r('app.media.ic_hud_success'),imgWidth: 40})} else if (OverlayType.fail == this.olConfig.type) {// messageOverlayScaleImage({src: $r('app.media.ic_hud_fail'),imgWidth: 30})}Text(this.olConfig.message).fontSize(14).fontColor($r('app.color.white')).margin({top: 10,})}.padding({top: 20,bottom: 20,left: 15,right: 15}).justifyContent(FlexAlign.Center).constraintSize({minWidth: 180,minHeight: 80,}).backgroundColor($r('app.color.overlay_bg_color')).borderRadius(10).offset(this.olConfig.offset)}
}
  • 2.CustomOverlayStorage

由于在OverlayManager来添加、删除、隐藏、显示节点过程中,需要使用index索引参数。这里使用一个类,类中有一个数组记录一下展示的节点Component

@ObservedV2
export class CustomOverlayStorage {@Trace contentArray: ComponentContent<OverlayConfig>[] = []
}
  • 3.自定义MyOverlayManager进行封装OverlayManager

首先确定属性uiContext,创建ComponentContent需要该参数,这个我在index.ets中进行初始化传入。
CustomOverlayStorage存储ComponentContent的数组,确定index
overlayManager用来来添加、删除、隐藏、显示节点

MyOverlayManager代码如下

/// 用于管理Overlay
/// 浮层(OverlayManager) 用于将自定义的UI内容展示在页面(Page)之上,
/// 在Dialog、Popup、Menu、BindSheet、BindContentCover和Toast等组件之下,
/// 展示的范围为当前窗口安全区内。可适用于常驻悬浮等场景。
/// 与OverlayManager相关的属性推荐采用AppStorage来进行应用全局存储,以免切换页面后属性值发生变化从而导致业务错误。
import { AppStorageV2, ComponentContent, OverlayManager, router } from '@kit.ArkUI';
import {builderCustomOverlayView,CustomOverlayStorage,OverlayConfig
} from '../common/components/hud/CustomOverlayView';export class MyOverlayManager {private static currentIndex: number = 0;private uiContext?: UIContextprivate overlayManager?: OverlayManagerprivate overlayStorage: CustomOverlayStorage =AppStorageV2.connect(CustomOverlayStorage, 'overlayStorage', () => new CustomOverlayStorage())!;private static instance: MyOverlayManager;public static getInstance(): MyOverlayManager {if (MyOverlayManager.instance == null) {MyOverlayManager.instance = new MyOverlayManager();}return MyOverlayManager.instance;}initOverlayNode(uiContext: UIContext): void {this.uiContext = uiContext;this.overlayManager = uiContext.getOverlayManager();}addOverlayView(overlayConfig: OverlayConfig): void {if (this.uiContext != null && this.uiContext != undefined) {// 设置索引下标let index = MyOverlayManager.currentIndex++;overlayConfig.index = index;// 创建componentContentlet componentContent = new ComponentContent(this.uiContext!, wrapBuilder<[OverlayConfig]>(builderCustomOverlayView),overlayConfig)this.overlayStorage.contentArray.push(componentContent);if (this.overlayManager != null && this.overlayManager != undefined) {this.overlayManager.addComponentContent(componentContent, index)}}}hideOverlayView(index: number) {if (this.overlayManager != null && this.overlayManager != undefined) {if (index < this.overlayStorage.contentArray.length) {this.overlayManager.hideComponentContent(this.overlayStorage.contentArray[index])}}}showOverlayView(index: number) {if (this.overlayManager != null && this.overlayManager != undefined) {if (index < this.overlayStorage.contentArray.length) {this.overlayManager.showComponentContent(this.overlayStorage.contentArray[index])}}}removeOverlayView(index: number) {if (this.overlayManager != null && this.overlayManager != undefined) {if (index < this.overlayStorage.contentArray.length) {this.overlayManager.removeComponentContent(this.overlayStorage.contentArray[index])}}}removeAllOverlayView() {if (this.overlayManager != null && this.overlayManager != undefined) {this.overlayManager.hideAllComponentContents();for (let index: number = 0; index < this.overlayStorage.contentArray.length; index++) {this.overlayManager.removeComponentContent(this.overlayStorage.contentArray[index])}}}
}
  • 4.index.ets传入uiContext

初始化配置uiContext

aboutToAppear(): void {console.log("aboutToAppear");MyOverlayManager.getInstance().initOverlayNode(this.getUIContext());}
  • 5.调用OverlayManager进行显示加载中、加载成功、加载失败提示

定义type及message

let config = new OverlayConfig(message);config.type = OverlayType.loading;config.onCallback = (index: number)=>{MyOverlayManager.getInstance().removeOverlayView(index)}MyOverlayManager.getInstance().addOverlayView(config);

加载中、加载成功、加载失败的Util

import { MyOverlayManager } from "../../manager/MyOverlayManager";
import { OverlayConfig, OverlayType } from "../components/hud/CustomOverlayView";export class EasyLoadingHud {static showLoading(message: string) {let config = new OverlayConfig(message);config.type = OverlayType.loading;config.onCallback = (index: number)=>{MyOverlayManager.getInstance().removeOverlayView(index)}MyOverlayManager.getInstance().addOverlayView(config);}static showSuccess(message: string) {let config = new OverlayConfig(message);config.type = OverlayType.success;config.onCallback = (index: number)=>{MyOverlayManager.getInstance().removeOverlayView(index)}MyOverlayManager.getInstance().addOverlayView(config);}static showFail(message: string) {let config = new OverlayConfig(message);config.type = OverlayType.fail;config.onCallback = (index: number)=>{MyOverlayManager.getInstance().removeOverlayView(index)}MyOverlayManager.getInstance().addOverlayView(config);}
}
  • 6.页面调用EasyLoadingHud进行显示

可以在页面需要的地方调用EasyLoadingHud进行显示

代码如下

// 加载中
EasyLoadingHud.showLoading("加载中...")
// 加载成功
EasyLoadingHud.showSuccess("加载成功")
// 加载失败
EasyLoadingHud.showFail("加载失败")

四、小结

在开发过程中会遇到提示弹窗、加载中指示器、加载失败的toast等功能,这里是学习HarmonyOS鸿蒙开发的学习记录,如果对你有用,你可以点个赞哦~~。详细的文档还是以官方文档为主。

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

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

相关文章

【蓝桥杯选拔赛真题60】C++寻宝石 第十四届蓝桥杯青少年创意编程大赛 算法思维 C++编程选拔赛真题解

目录 C++寻宝石 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 五、运行结果 六、考点分析 七、推荐资料 C++寻宝石 第十四届蓝桥杯青少年创意编程大赛C++选拔赛真题 一、题目要求 1、编程实现 有N(1<N<100)个盒子排成一排,每个盒子都放…

ue5 蒙太奇,即上半身动画和下半身组合在一起,并使用。学习b站库得科技

本文核心 正常跑步动画端枪动画跑起来也端枪 正常跑步动画 端枪动画的上半身 跑起来也端枪 三步走&#xff1a; 第一步制作动画蒙太奇和插槽 第二步动画蓝图选择使用上半身动画还是全身动画&#xff0c;将上半身端枪和下半身走路结合 第三步使用动画蒙太奇 1.开始把&a…

2025年01月09日Github流行趋势

1. 项目名称&#xff1a;khoj 项目地址url&#xff1a;https://github.com/khoj-ai/khoj项目语言&#xff1a;Python历史star数&#xff1a;22750今日star数&#xff1a;1272项目维护者&#xff1a;debanjum, sabaimran, MythicalCow, aam-at, eltociear项目简介&#xff1a;你…

Idea-离线安装SonarLint插件地址

地址&#xff1a; SonarQube for IDE - IntelliJ IDEs Plugin | Marketplace 选择Install Plugin from Disk..&#xff0c;选中下载好的插件&#xff0c;然后重启idea

MT6706BL 同步整流 规格书

MT6706BL 是用于反激式变换器的高性能 65V 同步整流器。MT6706BL兼容各种反激转换器类型。MT6706BL 支持 DCM、CCM 和准谐振模式。MT6706BL 集 成 了 一 个 65V 功 率MOSFET&#xff0c;可以取代肖特基二极管&#xff0c;提高效率。V SW <V TH-ON 时&#xff0c;MT6706BL 内…

linux centos挂载未分配的磁盘空间

使用到的命令 lshw -class disk -short hostnamectl fdisk /dev/sdb partprobe /dev/sdb mount /dev/sdb2 /opt/fastdfs/ mkfs.ext4 /dev/sdb2 mount -t ext4 /dev/sdb2 /opt/fastdfs/

在 macOS 中,设置自动将文件夹排在最前

文章目录 1、第一步访达设置2、第二步排序方式 需要两步设置 1、第一步访达设置 按名称排序的窗口中 2、第二步排序方式 选择名称

【LeetCode Hot100 贪心算法】 买卖股票的最佳时机、跳跃游戏、划分字母区间

贪心算法 买卖股票的最佳时机买卖股票的最佳时机II跳跃游戏跳跃游戏II划分字母区间 买卖股票的最佳时机 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的…

人工智能-机器学习之多元线性回归(项目实践一)

目标&#xff1a;运用scikit-learn进行多元线性回归方程的构建&#xff0c;通过实际案例的训练集和测试集进行预测&#xff0c;最终通过预测结果和MSE来评估预测的精度。 一、首先安装scikit-learn&#xff1a;pip install scikit-learn C:\Users\CMCC\PycharmProjects\AiPro…

MySql根据经纬度查询距离

一、搭建测试 创建数据表() CREATE TABLE sys_test (id int(11) NOT NULL AUTO_INCREMENT COMMENT 主键ID,name varchar(20) DEFAULT NULL COMMENT 名称,longitude decimal(10,6) DEFAULT NULL COMMENT 经度,latitude decimal(10,6) DEFAULT NULL COMMENT 维度,PRIMARY KEY (id…

api开发如何在代码中使用京东商品详情接口的参数?

选择编程语言和相关工具 以 Python 为例&#xff0c;你可以使用requests库来发送 HTTP 请求获取接口数据。如果是 Java&#xff0c;可以使用OkHttp等库。 Python 示例 假设你已经安装了requests库&#xff0c;以下是一个简单的代码示例来获取和使用京东商品详情接口参数&#…

【可实战】Bug的判定标准、分类、优先级、定位方法、提交Bug(包含常见面试题)

一、Bug相关概念 &#xff08;一&#xff09;bug判定标准 &#xff08;二&#xff09;常见 Bug 分类 &#xff08;三&#xff09;bug优先级 1.bug严重程度与优先级的关系 有些很严重的Bug&#xff0c;只在极端的条件下才出现&#xff0c;用户碰到的概率很低&#xff0c;这种情…

SpringBoot之核心配置

学习目标&#xff1a; 1.熟悉Spring Boot全局配置文件的使用 2.掌握Spring Boot配置文件属性值注入 3.熟悉Spring Boot自定义配置 4.掌握Profile多环境配置 5.了解随机值设置以及参数间引用 1.全局配置文件 Spring Boot使用 application.properties 或者application.yaml 的文…

GitLab创建用户,设置访问SSH Key

继上一篇 Linux Red Hat 7.9 Server安装GitLab-CSDN博客 安装好gitlab&#xff0c;启用管理员root账号后&#xff0c;开始创建用户账户 1、创建用户账户 进入管理后台页面 点击 New User 输入用户名、邮箱等必填信息和登录密码 密码最小的8位&#xff0c;不然会不通过 拉到…

1688平台商品关键词搜索的多样性与Python爬虫应用实践

在当今这个信息化、数字化飞速发展的时代&#xff0c;电子商务平台已经成为人们日常生活中不可或缺的一部分。而1688作为国内知名的B2B电商平台&#xff0c;凭借其庞大的商品种类和丰富的供应链资源&#xff0c;为无数商家和消费者提供了便捷的交易渠道。除了广受关注的女装品类…

为深度学习引入张量

为深度学习引入张量 什么是张量&#xff1f; 神经网络中的输入、输出和转换都是使用张量表示的&#xff0c;因此&#xff0c;神经网络编程大量使用张量。 张量是神经网络使用的主要数据结构。 张量的概念是其他更具体概念的数学概括。让我们看看一些张量的具体实例。 张量…

点击底部的 tabBar 属于 wx.switchTab 跳转方式,目标页面的 onLoad 不会触发(除非是第一次加载)

文章目录 1. tabBar 的跳转方式2. tabBar 跳转的特点3. 你的配置分析4. 生命周期触发情况5. 总结 很多人不明白什么是第一次加载&#xff0c;两种情况讨论&#xff0c;第一种情况假设我是开发者&#xff0c;第一次加载就是指点击微信开发者工具上边的编译按钮&#xff0c;每点击…

Tauri教程-基础篇-第二节 Tauri的核心概念上篇

“如果结果不如你所愿&#xff0c;就在尘埃落定前奋力一搏。”——《夏目友人帐》 “有些事不是看到了希望才去坚持&#xff0c;而是因为坚持才会看到希望。”——《十宗罪》 “维持现状意味着空耗你的努力和生命。”——纪伯伦 Tauri 技术教程 * 第四章 Tauri的基础教程 第二节…

Sql 创建用户

Sql server 创建用户 Sql server 创建用户SQL MI 创建用户修改其他用户密码 Sql server 创建用户 在对应的数据库执行&#xff0c;该用户得到该库的所有权限 test.database.chinacloudapi.cn DB–01 DB–02 创建服务器登录用户 CREATE LOGIN test WITH PASSWORD zDgXI7rsafkak…

Ubuntu 20.04安装gcc

一、安装GCC 1.更新包列表 user596785154:~$ sudo apt update2.安装gcc user596785154:~$ sudo apt install gcc3.验证安装 user596785154:~$ gcc --version二 编译C文件 1.新建workspace文件夹 user596785154:~$ mkdir workspace2.进入workspace文件夹 user596785154:~…