HarmonyOS Next中的弹出框使用

HarmonyOS Next弹出框概述及分类

弹出框是一种模态窗口,通常用于在保持当前上下文环境的同时,临时展示用户需关注的信息或待处理的操作。用户需在模态弹出框内完成相关交互任务之后,才能退出模态模式。弹出框可以不与任何组件绑定,其内容通常由多种组件组成,如文本、列表、输入框、图片等,以实现布局。ArkUI当前提供了自定义固定样式两类弹出框组件。

  • 自定义弹出框: 开发者需要根据使用场景,传入自定义组件填充在弹出框中实现自定义的弹出框内容。主要包括基础自定义弹出框 (CustomDialog)、不依赖UI组件的自定义弹出框 (openCustomDialog)。
  • 固定样式弹出框: 开发者可使用固定样式弹出框,指定需要显示的文本内容和按钮操作,完成简单的交互效果。主要包括警告弹窗 (AlertDialog)、列表选择弹窗 (ActionSheet)、选择器弹窗 (PickerDialog)、对话框 (showDialog)、操作菜单 (showActionMenu)。

本文主要是介绍自定义弹出框的使用,固定样式弹出框可以参考官方文档,自定义弹出框主要有两种实现方式:

1、基础自定义弹出框 (CustomDialog)(不推荐)

2、不依赖UI组件的全局自定义弹出框 (openCustomDialog)(推荐)

基础自定义弹出框 (CustomDialog)

CustomDialog是自定义弹出框,可用于广告、中奖、警告、软件更新等与用户交互响应操作。通过CustomDialogController类显示自定义弹窗。使用弹窗组件时,可优先考虑自定义弹窗,便于自定义弹窗的样式与内容。

1、@CustomDialog装饰器

使用@CustomDialog装饰器装饰自定义弹出框,可在此装饰器内自定义弹出框内容。这里在装饰器内添加确定和取消按钮,也可以同时添加数据函数。

TypeScript 复制代码
@CustomDialog
struct CustomDialogExample {
  cancel?: () => void
  confirm?: () => void
  controller: CustomDialogController

  build() {
    Column() {
      Text('我是内容').fontSize(20).margin({ top: 10, bottom: 10 })
      Flex({ justifyContent: FlexAlign.SpaceAround }) {
        Button('cancel')
          .onClick(() => {
            this.controller.close()
            if (this.cancel) {
              this.cancel()
            }
          }).backgroundColor(0xffffff).fontColor(Color.Black)
        Button('confirm')
          .onClick(() => {
            this.controller.close()
            if (this.confirm) {
              this.confirm()
            }
          }).backgroundColor(0xffffff).fontColor(Color.Red)
      }.margin({ bottom: 10 })
    }
  }
}

创建构造器,与装饰器呼应相连。页面内需要在构造器内进行接收,同时创建相应的函数操作。

TypeScript 复制代码
@Entry
@Component
struct CustomDialogUser {
  dialogController: CustomDialogController = new CustomDialogController({
    builder: CustomDialogExample({
      cancel: ()=> { this.onCancel() },
      confirm: ()=> { this.onAccept() },
    }),
  })

  onCancel() {
    console.info('Callback when the first button is clicked')
  }

  onAccept() {
    console.info('Callback when the second button is clicked')
  }

  build() {
    Column() {
      Button('click me')
        .onClick(() => {
          this.dialogController.open()
        })
    }.width('100%').margin({ top: 5 })
  }
}
2、CustomContentDialog

使用CustomContentDialog自定义弹出框,可在此自定义内容区弹出框,同时支持定义操作区按钮样式。从API version 12开始支持使用。

|-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------|---------------|----------------------------------------------------|
| 名称 | 类型 | 必填 | 装饰器类型 | 说明 |
| controller | CustomDialogController | 是 | - | 弹出框控制器。 说明: 未使用@Require装饰,构造时不强制校验参数。 |
| contentBuilder | () => void | 是 | @BuilderParam | 弹出框内容。 |
| primaryTitle | ResourceStr | 否 | - | 弹出框标题。 |
| secondaryTitle | ResourceStr | 否 | - | 弹出框辅助文本。 |
| localizedContentAreaPadding | LocalizedPadding | 否 | - | 弹出框内容区内边距。 |
| contentAreaPadding | Padding | 否 | - | 弹出框内容区内边距。设置了localizedContentAreaPadding属性时该属性不生效。 |
| buttons | ButtonOptions[] | 否 | - | 弹出框操作区按钮,最多支持4个按钮。 |
| theme | Theme| CustomTheme | 否 | - | 主题信息,可以是CustomTheme或从onWillApplyTheme中获取的Theme实例。 |
| themeColorMode | ThemeColorMode | 否 | - | 自定义弹窗深浅色模式。 |

支持自定义内容弹出框,包含contentBuilder、buttons等内容。和@CustomDialog装饰器一样,CustomContentDialog也可以添加按钮和数据,如果需要完全自定义弹框样式,可以只设置contentBuilder函数参数用来实现自定义弹框。

TypeScript 复制代码
import { CustomContentDialog } from '@kit.ArkUI'

@Entry
@Component
struct Index {
  dialogController: CustomDialogController = new CustomDialogController({
    builder: CustomContentDialog({
      primaryTitle: '标题',
      secondaryTitle: '辅助文本',
      contentBuilder: () => {
        this.buildContent();
      },
      buttons: [
        { 
          value: '按钮1',
          buttonStyle: ButtonStyleMode.TEXTUAL, 
          action: () => {
            console.info('Callback when the button is clicked')
          }
        },
        {
          value: '按钮2',
          buttonStyle: ButtonStyleMode.TEXTUAL,
          role: ButtonRole.ERROR
        }
      ],
    }),
  });

  build() {
    Column() {
      Button("支持自定义内容弹出框")
        .onClick(() => {
          this.dialogController.open()
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
  
  // 自定义弹出框的内容区
  @Builder
  buildContent(): void {
    Column() {
      Text('内容区')
    }
    .width('100%')
  }
}

不依赖UI组件的全局自定义弹出框 (openCustomDialog)

先对于CustomDialogController,官方更推荐我们使用openCustomDialog来实现自定义弹出框。

由于CustomDialogController在使用上存在诸多限制,不支持动态创建也不支持动态刷新,在相对较复杂的应用场景中推荐使用UIContext中获取到的PromptAction对象提供的openCustomDialog接口来实现自定义弹出框。

弹出框(openCustomDialog)存在两种入参方式创建自定义弹出框:

  • openCustomDialog(传参为ComponentContent形式):通过ComponentContent封装内容可以与UI界面解耦,调用更加灵活,可以满足开发者的封装诉求。拥有更强的灵活性,弹出框样式是完全自定义的,且在弹出框打开之后可以使用updateCustomDialog方法动态更新弹出框的一些参数。
  • openCustomDialog(传builder的形式):相对于ComponentContent,builder必须要与上下文做绑定,与UI存在一定耦合。此方法有用默认的弹出框样式,适合于开发者想要实现与系统弹窗默认风格一致的效果。
1、初始化弹出框配置

获取PromptAction对象,初始化弹出框配置,可在配置中修改弹窗位置,动画等相关配置。

创建ComponentContent,ComponentContent用于定义自定义弹出框的内容。其中,wrapBuilder(radioDialogView)封装自定义组件。

TypeScript 复制代码
  // 设置对话框内容组件(支持链式调用)
  init(context: UIContext, radioSelectBean: RadioSelectBean): RadioAppDialog {
    this.contentNode = new ComponentContent(context, wrapBuilder<[RadioSelectBean]>(radioDialogView), radioSelectBean);
    this.promptAction = context.getPromptAction();
    this.options = {
      alignment: DialogAlignment.Bottom,
      transition: TransitionEffect.move(TransitionEdge.BOTTOM)
        .animation({ duration: 300 }),
    }
    return this
  }
2、打开自定义弹出框。

通过调用openCustomDialog接口打开的弹出框默认为customStyle为true的弹出框,即弹出框的内容样式完全按照contentNode自定义样式显示。

TypeScript 复制代码
 // 显示自定义对话框
  show() {
    if (this.contentNode !== null) {
      this.promptAction?.openCustomDialog(this.contentNode, this.options)
        .then(() => {
          console.info('打开自定义对话框完成')
        })
        .catch((error: BusinessError) => {
          // 错误处理:获取错误码和信息
          let message = (error as BusinessError).message;
          let code = (error as BusinessError).code;
          console.error(`打开对话框参数错误,错误码:${code},信息:${message}`);
        })
    }
  }
3、关闭自定义弹出框

关闭弹出框之后若需要释放对应的ComponentContent,则需要调用ComponentContent的dispose方法。

tip:关闭弹出框需要传人待关闭的ComponentContent对象。

TypeScript 复制代码
 // 关闭自定义对话框
  close() {
    if (this.contentNode !== null) {
      this.promptAction?.closeCustomDialog(this.contentNode)
        .then(() => {
          this.contentNode?.dispose()
          console.info('关闭自定义对话框完成')
        })
        .catch((error: BusinessError) => {
          let message = (error as BusinessError).message;
          let code = (error as BusinessError).code;
          console.error(`关闭对话框参数错误,错误码:${code},信息:${message}`);
        })
    }
  }
4、更新自定义弹出框的内容

若需要更新弹出框中自定义组件的内容可以通过ComponentContent提供的update方法来实现。这里传人的数据对象就事显示的时候传人的数据。

TypeScript 复制代码
  //更新对话框数据
  updateData(radioSelectBean: RadioSelectBean) {
    this.contentNode?.update(radioSelectBean)
  }
5、完整代码
TypeScript 复制代码
// 导入ArkUI的对话框操作模块和基础服务错误类型
import { ComponentContent, curves, PromptAction, promptAction } from "@kit.ArkUI";
import { BusinessError } from "@kit.BasicServicesKit";
import { RadioSelectBean } from "../model/HomeModel";
import { radioDialogView } from "../view/GlobalBuildView";

// 自定义单选对话框类
export class RadioAppDialog {
  // 单例实例
  private static instance: RadioAppDialog;
  // 静态属性声明
  contentNode?: ComponentContent<Object>; // 对话框内容组件
  options?: promptAction.BaseDialogOptions; // 对话框基础配置选项
  promptAction?: PromptAction

  // 私有化构造函数
  private constructor() {
    console.info('创建自定义对话框单例');
  }

  /**
   * 获取单例实例(静态方法)
   * @returns 返回全局唯一实例
   */
  public static getInstance(): RadioAppDialog {
    if (!RadioAppDialog.instance) {
      RadioAppDialog.instance = new RadioAppDialog();
    }
    return RadioAppDialog.instance;
  }

  /**
   * 重置单例实例(用于测试或特殊场景)
   */
  public static resetInstance(): void {
    RadioAppDialog.instance = new RadioAppDialog();
  }


  // 设置对话框内容组件(支持链式调用)
  init(context: UIContext, radioSelectBean: RadioSelectBean): RadioAppDialog {
    this.contentNode = new ComponentContent(context, wrapBuilder<[RadioSelectBean]>(radioDialogView), radioSelectBean);
    this.promptAction = context.getPromptAction();
    this.options = {
      alignment: DialogAlignment.Bottom,
      transition: TransitionEffect.move(TransitionEdge.BOTTOM)
        .animation({ duration: 300 }),
    }
    return this
  }

  // 设置对话框选项(支持链式调用)
  setOptions(options: promptAction.BaseDialogOptions): RadioAppDialog {
    this.options = options;
    return this;
  }

  //更新对话框数据
  updateData(obj?: Object) {
    this.contentNode?.update(obj)
  }


  // 显示自定义对话框
  show() {
    if (this.contentNode !== null) {
      this.promptAction?.openCustomDialog(this.contentNode, this.options)
        .then(() => {
          console.info('打开自定义对话框完成')
        })
        .catch((error: BusinessError) => {
          // 错误处理:获取错误码和信息
          let message = (error as BusinessError).message;
          let code = (error as BusinessError).code;
          console.error(`打开对话框参数错误,错误码:${code},信息:${message}`);
        })
    }
  }

  // 关闭自定义对话框
  close() {
    if (this.contentNode !== null) {
      this.promptAction?.closeCustomDialog(this.contentNode)
        .then(() => {
          this.contentNode?.dispose()
          console.info('关闭自定义对话框完成')
        })
        .catch((error: BusinessError) => {
          let message = (error as BusinessError).message;
          let code = (error as BusinessError).code;
          console.error(`关闭对话框参数错误,错误码:${code},信息:${message}`);
        })
    }
  }

  // 更新对话框配置
  updateDialog(options: promptAction.BaseDialogOptions) {
    if (this.contentNode !== null) {
      this.promptAction?.updateCustomDialog(this.contentNode, options)
        .then(() => {
          console.info('更新对话框配置完成')
        })
        .catch((error: BusinessError) => {
          let message = (error as BusinessError).message;
          let code = (error as BusinessError).code;
          console.error(`更新对话框参数错误,错误码:${code},信息:${message}`);
        })
    }
  }
}
相关推荐
lucky志1 小时前
探秘鸿蒙 HarmonyOS NEXT:实战用 CodeGenie 构建鸿蒙应用页面
harmonyos·arkts
飞龙AI2 小时前
鸿蒙NEXT上传图片功能PhotoViewPicker核心功能解析
harmonyos·arkts
HarmonyOS小助手3 小时前
【鸿蒙生态学堂04】ArkUI开发基础(上)
harmonyos·鸿蒙·harmonyos next·arkui(方舟ui框架)介绍·使用常用组件构建页面·harmonyos 5.0·鸿蒙5·鸿蒙课程·鸿蒙生态
枫叶丹46 小时前
【HarmonyOS Next之旅】DevEco Studio使用指南(三十)
华为·harmonyos·deveco studio·harmonyos next
IUings21 小时前
【鸿蒙】HarmonyOS NEXT之如何正常加载地图组件
开发语言·华为·harmonyos·harmonyos next·地图服务·map kit
lucky志1 天前
探秘鸿蒙 HarmonyOS NEXT:一起了解鸿蒙的 AI 编程助手——CodeGenie!
harmonyos·arkts
SuperHeroWu72 天前
【 HarmonyOS 5 入门系列 】鸿蒙HarmonyOS示例项目讲解
华为·harmonyos·arkts·讲解·arkui·空ability示例项目
simple丶2 天前
【HarmonyOS】项目工程化工具 持续更迭...
harmonyos·arkts·arkui
simple丶4 天前
HarmonyOS 鸿蒙应用 - NEWS项目详细介绍
harmonyos·arkts·arkui