《级联年度选择》二、CustomDialog使用指南
HarmonyOS ArkTS 自定义弹窗(CustomDialog)使用指南
本文系统讲解 HarmonyOS 中自定义弹窗
@CustomDialog的完整使用方法,从基本概念到实战示例,帮助你掌握 CustomDialogController 的核心 API 和弹窗开发全流程。
效果
一、CustomDialog 概述
1.1 什么是 CustomDialog
CustomDialog是 ArkUI 提供的自定义弹窗机制,允许开发者通过@CustomDialog装饰器定义弹窗内容,并通过CustomDialogController控制器管理弹窗的显示与隐藏。
与系统默认弹窗(如AlertDialog)相比,CustomDialog具有更高的灵活性,可以自由定制弹窗的布局、样式和交互逻辑,适用于广告展示、确认对话框、信息录入、筛选面板等场景。
1.2 核心组成
| 组成部分 | 说明 |
|---|---|
@CustomDialog装饰器 | 标记一个 struct 为自定义弹窗组件 |
CustomDialogController | 控制器类,负责弹窗的创建、打开和关闭 |
open()方法 | 显示弹窗 |
close()方法 | 关闭弹窗 |
二、CustomDialogController 详解
2.1 基本用法
CustomDialogController必须在@Component的 struct 内部声明为成员变量并赋值才有效:
dialogController:CustomDialogController=newCustomDialogController({builder:MyCustomDialog(),// 弹窗内容构建器autoCancel:true,// 点击遮罩层是否关闭alignment:DialogAlignment.Center,// 弹窗对齐方式customStyle:false,// 是否使用自定义样式})2.2 配置参数一览
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
builder | CustomDialog | 必选 | 自定义弹窗的内容构建器 |
cancel | () => void | - | 点击遮罩层、返回键、ESC 键退出时的回调 |
autoCancel | boolean | true | 是否允许点击遮罩层关闭弹窗 |
alignment | DialogAlignment | Default | 弹窗对齐方式:Center/Top/Bottom |
offset | Offset | - | 弹窗相对对齐位置的偏移量 |
customStyle | boolean | false | true时使用自定义样式,去除系统默认背景和圆角 |
cornerRadius | number | Resource | - | 弹窗圆角半径 |
width | string | number | - | 弹窗宽度 |
height | string | number | - | 弹窗高度 |
borderWidth | number | - | 边框宽度 |
borderColor | Color | - | 边框颜色 |
onWillDismiss | (action) => void | - | 弹窗即将关闭时的拦截回调(API 12+) |
2.3 控制器方法
| 方法 | 说明 |
|---|---|
open() | 显示弹窗。可多次调用,但如果弹窗已显示则不会重复弹出 |
close() | 关闭弹窗。如果已关闭则不生效 |
三、定义自定义弹窗组件
3.1 基本结构
使用@CustomDialog和@Component同时装饰 struct,并声明controller属性:
@Component@CustomDialogstruct MyCustomDialog{controller:CustomDialogController|null=nullbuild(){Column({space:16}){Text('弹窗标题').fontSize(18).fontWeight(FontWeight.Bold)Text('这里是弹窗的内容区域').fontSize(14)Button('关闭').onClick(()=>{this.controller?.close()})}.padding(24)}}重要:
controller属性是必须的。如果不声明,编译器会报错:@CustomDialog component should have a property of the CustomDialogController type.
3.2 数据传递
弹窗组件可以通过@Link、@Prop等装饰器与父组件进行数据同步:
| 装饰器 | 数据方向 | 说明 |
|---|---|---|
@Link | 双向绑定 | 弹窗内修改数据会同步到父组件 |
@Prop | 单向传递 | 父组件数据传入弹窗,弹窗内修改不影响父组件 |
@Consume/@Provide | 跨层级 | 适用于多层嵌套的数据共享 |
四、完整实战示例:用户反馈弹窗
4.1 效果说明
- 主页面有一个"提交反馈"按钮
- 点击按钮弹出自定义弹窗,包含评分选择、文本输入和提交/取消按钮
- 提交后弹窗关闭,主页面显示反馈结果
- 支持点击遮罩层关闭
- 弹窗从底部弹出,带有圆角效果
4.2 弹窗组件代码
// FeedbackDialog.ets@Component@CustomDialogexportstruct FeedbackDialog{controller:CustomDialogController|null=null@Staterating:number=5@StatefeedbackText:string=''onSubmit?:(rating:number,text:string)=>voidonCancel?:()=>voidbuild(){Column({space:16}){// 标题行Row(){Text('提交反馈').fontSize(18).fontWeight(FontWeight.Bold).layoutWeight(1)Text('✕').fontSize(20).onClick(()=>{this.controller?.close()if(this.onCancel){this.onCancel()}})}.width('100%')// 评分区域Row({space:8}){ForEach([1,2,3,4,5],(star:number)=>{Text(star<=this.rating?'★':'☆').fontSize(28).fontColor(star<=this.rating?'#FFC107':'#CCCCCC').onClick(()=>{this.rating=star})})}.width('100%').justifyContent(FlexAlign.Center)// 输入区域TextArea({placeholder:'请输入您的反馈意见(选填)',text:this.feedbackText}).height(100).fontSize(14).backgroundColor('#F5F5F5').borderRadius(8).onChange((value:string)=>{this.feedbackText=value})// 按钮区域Row({space:12}){Button('取消').fontSize(14).backgroundColor('#F0F0F0').fontColor('#666666').layoutWeight(1).onClick(()=>{this.controller?.close()if(this.onCancel){this.onCancel()}})Button('提交').fontSize(14).backgroundColor('#4FC3F7').fontColor(Color.White).layoutWeight(1).onClick(()=>{this.controller?.close()if(this.onSubmit){this.onSubmit(this.rating,this.feedbackText)}})}.width('100%')}.padding(24).width('100%')}}4.3 主页面代码
// FeedbackPage.etsimport{FeedbackDialog}from'../components/FeedbackDialog'@Entry@Componentstruct FeedbackPage{@StatefeedbackResult:string=''@StatehasSubmitted:boolean=falsedialogController:CustomDialogController=newCustomDialogController({builder:FeedbackDialog({onSubmit:(rating:number,text:string)=>{this.feedbackResult=`评分:${rating}星 | 反馈:${text||'无'}`this.hasSubmitted=true},onCancel:()=>{this.feedbackResult='已取消提交'this.hasSubmitted=true}}),autoCancel:true,alignment:DialogAlignment.Bottom,customStyle:true,cornerRadius:16,width:'100%',offset:{dx:0,dy:0}})build(){Column({space:20}){Text('反馈中心').fontSize(22).fontWeight(FontWeight.Bold).margin({top:24})Button('提交反馈',{type:ButtonType.Capsule}).fontSize(16).backgroundColor('#4FC3F7').fontColor(Color.White).width(200).onClick(()=>{this.dialogController.open()})if(this.hasSubmitted){Column({space:8}){Text('最近提交结果').fontSize(14).fontColor('#888888')Text(this.feedbackResult).fontSize(15).padding(12).backgroundColor('#F5F5F5').borderRadius(8).width('100%')}.padding(16).margin({top:8})}Blank()}.width('100%').height('100%').padding({left:16,right:16}).backgroundColor('#FAFAFA')}}4.4 关键代码解析
(1)弹窗控制器配置
dialogController:CustomDialogController=newCustomDialogController({builder:FeedbackDialog({...}),alignment:DialogAlignment.Bottom,// 从底部弹出customStyle:true,// 使用自定义样式cornerRadius:16,// 圆角 16vp})customStyle: true去除了系统默认的弹窗背景和圆角,让弹窗完全按照自定义布局显示。
(2)弹窗内回调机制
通过函数属性onSubmit和onCancel实现弹窗与父组件的通信。弹窗关闭前调用回调函数,将数据传递给父组件。
(3)弹窗关闭
this.controller?.close()使用可选链调用close()方法,确保 controller 存在时才执行关闭操作。
五、onWillDismiss 拦截关闭(API 12+)
onWillDismiss允许在弹窗即将关闭时进行拦截判断,根据关闭原因决定是否真正关闭:
dialogController:CustomDialogController=newCustomDialogController({builder:MyDialog(),onWillDismiss:(dismissAction:DismissDialogAction)=>{// 根据关闭原因判断if(dismissAction.reason===DismissReason.PRESS_BACK){dismissAction.dismiss()// 允许返回键关闭}if(dismissAction.reason===DismissReason.TOUCH_OUTSIDE){// 不关闭,继续显示弹窗}if(dismissAction.reason===DismissReason.CLOSE_BUTTON){dismissAction.dismiss()}}})DismissReason枚举值:
| 值 | 说明 |
|---|---|
PRESS_BACK | 用户按返回键 |
TOUCH_OUTSIDE | 点击遮罩层 |
CLOSE_BUTTON | 调用 close 方法 |
六、最佳实践与注意事项
6.1 注意事项
| 注意点 | 说明 |
|---|---|
| 弹窗不支持动态刷新参数 | CustomDialogController的配置参数在初始化后不可更改 |
| 页面跳转不自动关闭 | 路由跳转时需手动调用close()关闭弹窗 |
| controller 销毁置空 | 组件销毁时建议将controller置为null |
| 避免弹窗嵌套 | 不要在弹窗内再弹出 SubWindow 模式的弹窗 |
6.2 使用建议
- 优先使用 CustomDialog:比
AlertDialog更灵活,可完全定制样式和交互。 - 数据同步用
@Link:需要弹窗与父组件双向同步数据时,使用@Link装饰器。 - 回调函数传结果:弹窗内操作结果通过回调函数传递给父组件,保持数据流向清晰。
- 使用
customStyle:需要自定义弹窗背景、圆角时,设置customStyle: true。 - 合理利用
alignment:底部弹窗用Bottom,确认弹窗用Center,适配不同场景。
七、参考链接
- CustomDialog 官方 API 文档
- CustomDialogController 参数说明
- 弹窗概述
