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() })@ComponentV2export struct LoadingHud { @Local message: string = '';
- aboutToAppear(): void {
- this.message = LocalStorage.getShared().get("message") ?? "";
- }
- build() { Column() { Column(){ Row() { // 从左往右,1号环形进度条,默认前景致为蓝色渐变,默认strokeWidth进度条宽度为2.0vp LoadingProgress() .color($r('app.color.success')) .width(40) .height(40) // message Text(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) }}
复制代码
在创建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?: CustomDialogController
- title?: string
- build() {
- Column() {
- Column() {
- // message
- Text(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
- // 自定义CustomDialog
- customDialogController: 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 = 0
- autoDismiss: boolean = true;
- duration: number = 3000 // 持续时间
- onCallback?: (index: number) => void
- type: OverlayType = OverlayType.loading
- constructor(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) {
- // message
- LoadingProgress()
- .color($r('app.color.success'))
- .width(40)
- .height(40)
- } else if (OverlayType.success == this.olConfig.type) {
- // message
- OverlayScaleImage({
- src: $r('app.media.ic_hud_success'),
- imgWidth: 40
- })
- } else if (OverlayType.fail == this.olConfig.type) {
- // message
- OverlayScaleImage({
- 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)
- }
- }
复制代码
由于在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?: UIContext
- private overlayManager?: OverlayManager
- private 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;
- // 创建componentContent
- let 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])
- }
- }
- }
- }
复制代码
初始化配置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); }}
复制代码
可以在页面必要的地方调用EasyLoadingHud进行显示
代码如下
- // 加载中
- EasyLoadingHud.showLoading("加载中...")
- // 加载成功
- EasyLoadingHud.showSuccess("加载成功")
- // 加载失败
- EasyLoadingHud.showFail("加载失败")
复制代码 四、小结
在开辟过程中会遇到提示弹窗、加载中指示器、加载失败的toast等功能,这里是学习HarmonyOS鸿蒙开辟的学习记录,假如对你有用,你可以点个赞哦~~。详细的文档还是以官方文档为主。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |