鸿蒙UI开发——全局自定义弹窗实现

1、前 言

我们在鸿蒙UI系统组件08------自定义弹窗(CustomDialog)文章中介绍到,我们可以通过CustomDialogController类显示自定义弹窗。

由于CustomDialogController在使用上存在诸多限制,例如:不支持动态创建、不支持动态刷新。

在相对较复杂的应用场景中我们使用UIContext中获取到的PromptAction对象提供的openCustomDialog接口来实现自定义弹窗。下面针对openCustomDialog的使用做一个简单介绍。

2、弹出自定义弹窗

在使用弹窗前,我们需要创建ComponentContent对象,ComponentContent用于定义自定义弹窗的内容。创建一个ComponentContent对象的实例代码如下(核心代码 23 ~ 24行):​​​​​

复制代码
import { ComponentContent } from '@kit.ArkUI';// 自定义弹窗的Builder函数(构建弹窗的内容)@Builderfunction buildText(params: Params) {  Column() {    Text(params.text)      .fontSize(50)      .fontWeight(FontWeight.Bold)      .margin({ bottom: 36 })    Button('Close')      .onClick(() => {        PromptActionClass.closeDialog()      })  }.backgroundColor('#FFF0F0F0')}@Entry@Componentstruct Index {  @State message: string = "鸿蒙自习室"  private ctx: UIContext = this.getUIContext();  private contentNode: ComponentContent<Object> =    new ComponentContent(this.ctx, wrapBuilder(buildText), new Params(this.message));  build() {  // ...  }}

其中,wrapBuilder(buildText)封装自定义组件,new Params(this.message)是自定义组件的入参,可以缺省,也可以传入基础数据类型。

通过调用openCustomDialog接口打开弹窗。代码如下:

复制代码
this.ctx.getPromptAction().openCustomDialog(this.contentNode, this.options)  .then(() => {    console.info('OpenCustomDialog complete.')  })  .catch((error: BusinessError) => {    let message = (error as BusinessError).message;    let code = (error as BusinessError).code;    console.error(`OpenCustomDialog args error code is ${code}, message is ${message}`);  })

3、关闭自定义弹窗

在弹出窗口的基础上,我们可以通过closeCustomDialog来关闭弹窗(关闭弹窗之后若需要释放对应的ComponentContent,则需要调用ComponentContent的dispose方法)。代码如下:​​​​​​​

复制代码
this.ctx.getPromptAction().closeCustomDialog(this.contentNode)  .then(() => {    console.info('CloseCustomDialog complete.')  })  .catch((error: BusinessError) => {    let message = (error as BusinessError).message;    let code = (error as BusinessError).code;    console.error(`CloseCustomDialog args error code is ${code}, message is ${message}`);  })

4、更新自定义弹窗的内容

ComponentContent与BuilderNode有相同的使用限制,不支持自定义组件使用@Reusable、@Link、@Provide、@Consume等装饰器,来同步弹窗弹出的页面与ComponentContent中自定义组件的状态。

因此,若需要更新弹窗中自定义组件的内容可以通过ComponentContent提供的update方法来实现。

复制代码
this.contentNode.update(new Params('update'))

5、更新自定义弹窗的属性

通过updateCustomDialog可以动态更新弹窗的属性。目前支持的属性包括alignment、offset、autoCancel、maskColor。

需要注意的是,更新属性时,未设置的属性会恢复为默认值。例如,初始设置{ alignment: DialogAlignment.Top, offset: { dx: 0, dy: 50 } },更新时设置{ alignment: DialogAlignment.Bottom },则初始设置的offset: { dx: 0, dy: 50 }不会保留,会恢复为默认值。​​​​​​​

复制代码
this.ctx.getPromptAction().updateCustomDialog(this.contentNode, options)  .then(() => {    console.info('UpdateCustomDialog complete.')  })  .catch((error: BusinessError) => {    let message = (error as BusinessError).message;    let code = (error as BusinessError).code;    console.error(`UpdateCustomDialog args error code is ${code}, message is ${message}`);  })

6、一个弹窗示例

示例效果如下:

👉🏻 先封装一个全局通用的工具类PromptActionClass.ts(用于弹窗/关闭弹窗/更新弹窗)​​​​​​​

复制代码
// PromptActionClass.tsimport { BusinessError } from '@kit.BasicServicesKit';import { ComponentContent, promptAction } from '@kit.ArkUI';import { UIContext } from '@ohos.arkui.UIContext';export class PromptActionClass {  static ctx: UIContext;  static contentNode: ComponentContent<Object>;  static options: promptAction.BaseDialogOptions;  static setContext(context: UIContext) {    PromptActionClass.ctx = context;  }  static setContentNode(node: ComponentContent<Object>) {    PromptActionClass.contentNode = node;  }  static setOptions(options: promptAction.BaseDialogOptions) {    PromptActionClass.options = options;  }  static openDialog() {    if (PromptActionClass.contentNode !== null) {      PromptActionClass.ctx.getPromptAction()        .openCustomDialog(PromptActionClass.contentNode, PromptActionClass.options)        .then(() => {          console.info('OpenCustomDialog complete.')        })        .catch((error: BusinessError) => {          let message = (error as BusinessError).message;          let code = (error as BusinessError).code;          console.error(`OpenCustomDialog args error code is ${code}, message is ${message}`);        })    }  }  static closeDialog() {    if (PromptActionClass.contentNode !== null) {      PromptActionClass.ctx.getPromptAction()        .closeCustomDialog(PromptActionClass.contentNode)        .then(() => {          console.info('CloseCustomDialog complete.')        })        .catch((error: BusinessError) => {          let message = (error as BusinessError).message;          let code = (error as BusinessError).code;          console.error(`CloseCustomDialog args error code is ${code}, message is ${message}`);        })    }  }  static updateDialog(options: promptAction.BaseDialogOptions) {    if (PromptActionClass.contentNode !== null) {      PromptActionClass.ctx.getPromptAction()        .updateCustomDialog(PromptActionClass.contentNode, options)        .then(() => {          console.info('UpdateCustomDialog complete.')        })        .catch((error: BusinessError) => {          let message = (error as BusinessError).message;          let code = (error as BusinessError).code;          console.error(`UpdateCustomDialog args error code is ${code}, message is ${message}`);        })    }  }}

👉🏻 在界面中需要弹出时,使用PromptActionClass,示例如下:​​​​​​​

复制代码
// Index.etsimport { ComponentContent } from '@kit.ArkUI';import { PromptActionClass } from './PromptActionClass';class Params {  text: string = ""  constructor(text: string) {    this.text = text;  }}@Builderfunction buildText(params: Params) {  Column() {    Text(params.text)      .fontSize(50)      .fontWeight(FontWeight.Bold)      .margin({ bottom: 36 })    Button('Close')      .onClick(() => {        PromptActionClass.closeDialog()      })  }.backgroundColor('#FFF0F0F0')}@Entry@Componentstruct Index {  @State message: string = "鸿蒙自习室"  private ctx: UIContext = this.getUIContext();  private contentNode: ComponentContent<Object> =    new ComponentContent(this.ctx, wrapBuilder(buildText), new Params(this.message));  aboutToAppear(): void {    PromptActionClass.setContext(this.ctx);    PromptActionClass.setContentNode(this.contentNode);    PromptActionClass.setOptions({ alignment: DialogAlignment.Top, offset: { dx: 0, dy: 50 } });  }  build() {    Row() {      Column() {        Button("弹出对话框后,1.5秒更新位置")          .margin({ top: 50 })          .onClick(() => {            this.message = '鸿蒙自习室';            PromptActionClass.openDialog()            setTimeout(() => {              PromptActionClass.updateDialog({                alignment: DialogAlignment.Bottom,                offset: { dx: 0, dy: -50 }              })            }, 1500)          })        Button("弹出对话框后,1.5秒更新文案")          .margin({ top: 50 })          .onClick(() => {            PromptActionClass.openDialog()            setTimeout(() => {              this.contentNode.update(new Params('harmony自习室'))            }, 1500)          })      }      .width('100%')      .height('100%')    }    .height('100%')  }}
相关推荐
贾伟康3 小时前
【句匠|20】HarmonyOS ArkTS AppGallery 发布复查实战:核对包名、版本、设备、素材和离线声明
harmonyos·arkts·应用上架·appgallery·发布审核
贾伟康3 小时前
【句匠|15】HarmonyOS ArkTS 本地状态持久化实战:让保存、删除和页面返回后的数据即时一致
harmonyos·arkts·数据持久化·appstorage·preferences
贾伟康6 小时前
【句匠|16】HarmonyOS ArkTS 多设备布局实战:适配手机、平板和 PC/2in1 的窗口变化
harmonyos·arkts·arkui·响应式布局·多设备适配
小雨青年6 小时前
【HarmonyOS 7 平行视界深度实战】03 购物模式怎么实现连续浏览和左右推挤
华为·harmonyos
SuperHeroWu78 小时前
HarmonyOS Dev Assistant (HarmonyOS开发助手)如何打通元服务开发全流程
ai·agent·harmonyos·vs code·元服务·hbuilderx·assistant
熊猫钓鱼>_>9 小时前
用 OHAudioSuite 空间渲染节点搭一座「3D 有声博物馆」——从三种模式到 FreeBuds 头追的实战记录
c++·3d·ai·harmonyos·arkts·audio·ohaudiosuite
OH_TPC9 小时前
HarmonyOS APP开发---"心动卡"社交匹配App,需要用到这个库
harmonyos
图扑软件9 小时前
下篇・换墨|主题/多语言/移动端,一套组件全覆盖
前端·javascript·ui·性能优化·数据可视化
光锥智能9 小时前
HUAWEI WATCH 6系列正式发布:鸿蒙AI手表,智慧健康旗舰
人工智能·华为·harmonyos
光锥智能10 小时前
HUAWEI WATCH Ultimate 2 非凡探索推出滑雪登山功能,专业数据助力探索雪域奇境
华为