HarmonyOS Next中的弹出框使用
HarmonyOS Next弹出框概述及分类
弹出框是一种模态窗口,通常用于在保持当前上下文环境的同时,临时展示用户需关注的信息或待处理的操作。用户需在模态弹出框内完成相关交互任务之后,才能退出模态模式。弹出框可以不与任何组件绑定,其内容通常由多种组件组成,如文本、列表、输入框、图片等,以实现布局。ArkUI当前提供了自定义和固定样式两类弹出框组件。
- 自定义弹出框: 开发者需要根据使用场景,传入自定义组件填充在弹出框中实现自定义的弹出框内容。主要包括基础自定义弹出框 (CustomDialog)、不依赖UI组件的自定义弹出框 (openCustomDialog)。
- 固定样式弹出框: 开发者可使用固定样式弹出框,指定需要显示的文本内容和按钮操作,完成简单的交互效果。主要包括警告弹窗 (AlertDialog)、列表选择弹窗 (ActionSheet)、选择器弹窗 (PickerDialog)、对话框 (showDialog)、操作菜单 (showActionMenu)。
本文主要是介绍自定义弹出框的使用,固定样式弹出框可以参考官方文档,自定义弹出框主要有两种实现方式:
1、基础自定义弹出框 (CustomDialog)(不推荐)
2、不依赖UI组件的全局自定义弹出框 (openCustomDialog)(推荐)
基础自定义弹出框 (CustomDialog)
CustomDialog是自定义弹出框,可用于广告、中奖、警告、软件更新等与用户交互响应操作。通过CustomDialogController类显示自定义弹窗。使用弹窗组件时,可优先考虑自定义弹窗,便于自定义弹窗的样式与内容。
1、@CustomDialog装饰器
使用@CustomDialog装饰器装饰自定义弹出框,可在此装饰器内自定义弹出框内容。这里在装饰器内添加确定和取消按钮,也可以同时添加数据函数。
@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 })
}
}
}
创建构造器,与装饰器呼应相连。页面内需要在构造器内进行接收,同时创建相应的函数操作。
@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函数参数用来实现自定义弹框。
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)封装自定义组件。
// 设置对话框内容组件(支持链式调用)
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自定义样式显示。
// 显示自定义对话框
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对象。
// 关闭自定义对话框
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方法来实现。这里传人的数据对象就事显示的时候传人的数据。
//更新对话框数据
updateData(radioSelectBean: RadioSelectBean) {
this.contentNode?.update(radioSelectBean)
}
5、完整代码
// 导入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}`);
})
}
}
}