当前位置: 首页 > news >正文

弹窗交互:AlertDialog与CustomDialog的创建与关闭(11)

在鸿蒙 ArkUI 开发中,弹窗是处理用户交互反馈(如警告、确认、自定义提示)的核心组件。根据官方文档与最佳实践,ArkUI 提供了固定样式的AlertDialog和高度可定制的CustomDialog

以下系统梳理这两种弹窗的创建、关闭及进阶封装方案。

一、 AlertDialog:轻量级警告弹窗

AlertDialog适用于简单的信息提示或需要用户进行“确认/取消”操作的场景。它由标题区、内容区和操作按钮区组成,无需开发者手动构建 UI 布局。

1. 基础用法(双按钮)

通过primaryButtonsecondaryButton配置两个操作按钮,并通过action回调处理点击逻辑。

Button('点击显示警告弹窗') .onClick(() => { AlertDialog.show({ title: '删除联系人', message: '是否删除所选的联系人?', autoCancel: true, // 点击遮罩层时是否自动关闭 primaryButton: { value: '取消', action: () => { console.info('点击了取消'); } }, secondaryButton: { value: '删除', fontColor: Color.Red, // 危险操作通常标红 action: () => { console.info('成功删除'); } } }); })
import { promptAction } from '@kit.ArkUI'; @Entry @Component struct AdvancedInputExample { @State username: string = ''; @State password: string = ''; @State searchKey: string = ''; build() { Column({ space: 20 }) { // 1. 账号输入框 TextInput({ placeholder: '请输入账号(仅限字母数字)', text: this.username }) .type(InputType.Normal) .maxLength(20) .inputFilter('[a-zA-Z0-9]') .onChange((value: string) => { this.username = value; }) .width('100%') .height(48) .backgroundColor('#F5F5F5') .borderRadius(8) .padding({ left: 15, right: 15 } as EdgeWidths) // 2. 密码输入框 TextInput({ placeholder: '请输入密码', text: this.password }) .type(InputType.Password) .maxLength(16) .caretColor('#007DFF') .placeholderColor('#CCCCCC') .onChange((value: string) => { this.password = value; }) .width('100%') .height(48) .backgroundColor('#F5F5F5') .borderRadius(8) .padding({ left: 15, right: 15 } as EdgeWidths) // 3. 搜索框 TextInput({ placeholder: '搜索商品或文章', text: this.searchKey }) .enterKeyType(EnterKeyType.Search) .onSubmit(() => { promptAction.showToast({ message: `开始搜索: ${this.searchKey}` }); }) .onBlur(() => { console.log('Search input lost focus'); }) .width('100%') .height(40) .backgroundColor('#EEEEEE') .borderRadius(20) .padding({ left: 15, right: 15 } as EdgeWidths) .fontSize(14) // 👇 【新增】警告弹窗按钮放在这里 Button('点击显示警告弹窗') .onClick(() => { AlertDialog.show({ title: '删除联系人', message: '是否删除所选的联系人?', autoCancel: true, // 点击遮罩层时是否自动关闭 primaryButton: { value: '取消', action: () => { console.info('点击了取消'); } }, secondaryButton: { value: '删除', fontColor: Color.Red, // 危险操作通常标红 action: () => { console.info('成功删除'); } } }); }) .width('100%') .height(48) .backgroundColor('#FF4D4F') .fontColor(Color.White) .borderRadius(8) } .padding(20) .width('100%') } }

2. 单按钮确认弹窗

如果仅需提示用户且只有一个确认动作,可以使用confirm属性替代双按钮配置。

AlertDialog.show({ title: '提示', message: '您的网络已断开!', confirm: { value: '知道了', action: () => { console.info('用户确认'); } } });

二、 CustomDialogController:基础自定义弹窗

当系统的固定样式无法满足需求(例如需要包含输入框、复杂图文排版)时,需使用CustomDialog。其核心是通过CustomDialogController来控制弹窗的生命周期。

1. 定义弹窗组件

使用@CustomDialog装饰器标记组件,并通过controller接收控制器实例以支持内部关闭。

@CustomDialog export struct CommonDialog { controller: CustomDialogController; @State inputValue: string = ''; build() { Column() { Text('请输入昵称').fontSize(18).fontWeight(FontWeight.Bold).margin({ top: 20, bottom: 10 }) TextInput({ placeholder: '请输入...', text: this.inputValue }) .height(40).borderRadius(8).backgroundColor('#F5F5F5') .onChange((value) => { this.inputValue = value; }) Row() { Button('取消').flex(1).backgroundColor('#F5F5F5').fontColor('#333333') .onClick(() => { this.controller.close(); }) Button('确认').flex(1).margin({ left: 12 }).backgroundColor('#007DFF') .onClick(() => { console.log('提交内容:', this.inputValue); this.controller.close(); }) }.width('100%').margin({ top: 20, bottom: 20 }) } .padding(20).backgroundColor(Color.White).borderRadius(12) } }
2. 页面调用与关闭

在宿主页面中初始化CustomDialogController,将自定义组件传入builder参数,并通过.open().close()方法控制显隐。

dialogController: CustomDialogController = new CustomDialogController({ builder: CommonDialog(), alignment: DialogAlignment.Center, cancelable: true // 允许点击外部蒙层关闭 }); // 打开弹窗 this.dialogController.open();

三、 进阶推荐:全局解耦的 openCustomDialog

1. CustomDialog 的双向数据通信(@Link)

在实际业务中,弹窗往往需要展示父页面的数据,并将用户在弹窗内的操作结果回传给父页面。官方推荐使用@Link装饰器实现父子状态同步。

// 自定义弹窗组件:接收外部传入的数据并回传 @CustomDialog export struct EditNameDialog { controller: CustomDialogController; @Link currentName: string; // 使用 @Link 实现双向绑定 build() { Column({ space: 20 }) { Text('修改昵称').fontSize(18).fontWeight(FontWeight.Bold) TextInput({ text: this.currentName }) .onChange((value: string) => { this.currentName = value; }) Button('保存') .onClick(() => { // 点击保存时,父页面的 @State 变量会自动更新为最新值 this.controller.close(); }) } .padding(20).backgroundColor(Color.White).borderRadius(12) } } // 父页面调用示例 @Entry @Component struct ProfilePage { @State userName: string = 'HarmonyOS_Dev'; dialogController: CustomDialogController = new CustomDialogController({ builder: EditNameDialog({ currentName: $userName }), // 使用 $ 传递引用 alignment: DialogAlignment.Center, customStyle: true }); build() { Column() { Text(`当前昵称: ${this.userName}`) Button('编辑昵称').onClick(() => { this.dialogController.open(); }) } } }
2. 高阶封装:开箱即用的通用业务弹窗 (CommonDialog)

为了避免每次遇到“标题+内容+双按钮”的需求都重写一遍CustomDialog,可以封装一个完全受控的通用组件,通过参数配置即可生成不同样式的弹窗。

// 定义统一的弹窗配置接口 export interface CommonDialogOptions { title?: string; content?: string; cancelText?: string; confirmText?: string; onCancel?: () => void; onConfirm?: () => void; } // 通用弹窗 UI 组件 @CustomDialog export struct CommonDialog { controller: CustomDialogController; options: CommonDialogOptions; build() { Column() { if (this.options.title) { Text(this.options.title).fontSize(18).fontWeight(FontWeight.Bold).margin({ top: 20, bottom: 10 }) } if (this.options.content) { Text(this.options.content).fontSize(14).fontColor('#666666').margin({ bottom: 20 }).textAlign(TextAlign.Center) } Row({ space: 12 }) { Button(this.options.cancelText || '取消') .flex(1).height(44).backgroundColor('#F5F5F5').fontColor('#333333') .onClick(() => { this.controller.close(); this.options.onCancel?.(); }) Button(this.options.confirmText || '确认') .flex(1).height(44).backgroundColor('#007DFF').fontColor(Color.White) .onClick(() => { this.controller.close(); this.options.onConfirm?.(); }) }.width('100%').margin({ bottom: 20 }) } .width('100%').padding({ left: 20, right: 20 }).backgroundColor(Color.White).borderRadius(12) } }
3. 蒙层控制与高级交互

在某些复杂场景下,我们需要对弹窗的背景蒙层进行精细控制,例如允许点击蒙层穿透到下层页面,或者自定义蒙层的颜色。

  • 非模态弹窗(背景可交互):将isModal设置为false,此时弹窗不会阻断底层页面的滑动或点击事件。
  • 自定义蒙层颜色:通过maskColor属性调整遮罩透明度,常用于引导页或夜间模式。
Button('显示非模态提示') .onClick(() => { AlertDialog.show({ title: '系统升级中', message: '请在后台等待,您可以继续浏览其他页面。', isModal: false, // 【关键】设为 false,允许用户与弹窗背后的页面交互 maskColor: '0x00000000', // 隐藏蒙层 confirm: { value: '知道了' } }); })
4. 生命周期回调与埋点监控

在大型项目中,我们通常需要知道弹窗何时真正渲染完成以触发埋点上报,或者在关闭后执行清理逻辑。ArkUI 提供了完整的时序回调支持:

AlertDialog.show({ title: '广告位', message: '限时优惠...', confirm: { value: '立即查看' }, onWillAppear: () => console.info('弹窗即将出现(动效前)'), onDidAppear: () => { console.info('弹窗已完全展示'); // 【业务场景】在这里触发曝光埋点上报 }, onWillDisappear: () => console.info('弹窗即将消失(动效前)'), onDidDisappear: () => { console.info('弹窗已彻底销毁'); // 【业务场景】在这里释放相关的定时器或监听器 } });

虽然CustomDialogController易于上手,但它在实际工程中存在诸多限制(不支持动态创建、刷新受限)。官方强烈推荐使用从UIContext获取的PromptAction对象提供的openCustomDialogAPI 来实现完全解耦的全局弹窗。

核心优势
  • 与 UI 解耦:通过ComponentContent封装内容,无需在每个页面都绑定 Controller。
  • 支持动态更新:弹窗打开后,可通过updateCustomDialog动态修改对齐方式、偏移量或蒙层颜色等属性。
  • 完善的生命周期:提供onWillAppearonDidAppearonWillDisappearonDidDisappear四个时序回调,方便做埋点或动画过渡。
最佳实践:封装静态工具类

为了避免在业务代码中重复编写冗长的ComponentContent创建与销毁逻辑,建议封装一个统一的DialogController工具类:

import { promptAction } from '@kit.ArkUI'; export class GlobalDialogUtil { private static dialogNode: ComponentContent<Object> | null = null; // 打开全局自定义弹窗 static show(builder: WrappedBuilder<[Object]>, params?: Object) { this.dismiss(); // 防止重复弹出 const ctx = getContext(this); this.dialogNode = new ComponentContent(ctx, builder, params); promptAction.openCustomDialog(this.dialogNode, { isModal: true, autoCancel: true, alignment: DialogAlignment.Center, maskColor: '0x33000000' }).then(() => { console.info('Global Dialog opened.'); }); } // 关闭并释放资源 static dismiss() { if (this.dialogNode) { promptAction.closeCustomDialog(this.dialogNode).then(() => { this.dialogNode?.dispose(); // 【关键】必须手动释放内存 this.dialogNode = null; }); } } }

💡 选型总结建议

  • 简单提示/确认:直接使用AlertDialog.show(),零成本接入。
  • 常规业务自定义弹窗:使用CustomDialogController
  • 全局通用弹窗/复杂交互/需要动态更新样式:务必采用PromptAction.openCustomDialog+ComponentContent模式,这是目前鸿蒙应用框架下最优雅、扩展性最强的弹窗解决方案。
http://www.jsqmd.com/news/984859/

相关文章:

  • 【系列预告】AI应用开发实战课:26篇教程覆盖 Prompt、RAG、Agent 与工程化
  • 常州金坛区黄金回收行情,六大机构对比与避坑指南 - 专业黄金回收
  • 波形护拦板厂家哪家更适合我:五类工程需求对应厂家推荐及对比指南 - 品牌2026
  • 【提示词工程】提示词工程笔记:从核心思想到实战代码
  • 【华为OD机试真题 新系统】1019、文档特征提取 | 机试真题+思路参考+代码解析(C++、Java、Py、C语言、JS)
  • 2026最新漳州市黄金回收价格一览表 避坑攻略与靠谱商家推荐 - 余生黄金回收
  • 从LINUX等平台高速连接Windows中的miniQMT_socket_server
  • Got timeout reading communication packets解决方法
  • 告别编译焦虑!Windows 10下用LLVM-MinGW和Ninja一键搞定OLLVM-14.x(附成品下载)
  • 别再截图了!用Altium Designer 23原生功能导出PCB高清丝印图,5分钟搞定SW贴图素材
  • 微信投票小程序怎么用丨图文视频投票制作全过程(海投票实时更新) - 微信投票小程序
  • 广州、佛山有技术实力的外贸GEO推广公司推荐。 - 热点速览
  • 别再死记硬背了!用一张图+对比表彻底搞懂Vue3自定义指令的生命周期
  • 通化黄金回收2026大盘价结算无套路攻略 - 润富黄金回收
  • Claude Code 超详细完整指南(手把手教学)
  • windows server RDP登录
  • AI小助手开发与应用(下):API迁移实践与多性格交互引擎
  • Redis 分布式锁进阶第一百二十七篇
  • 云南研学旅行包车公司排行:5家合规靠谱服务商盘点 - 奔跑123
  • 天津黄金回收店五大门店,耀辉优质:2026消费者避坑指南与正规品牌选择标准 - 奢侈品回收
  • 不只是混淆:手把手教你将OLLVM-14.x集成到Android Studio NDK,打造专属加固工具链
  • 2026潍坊防水补漏哪家靠谱?正规公司排名及避坑价格指南 - 苏易修缮
  • 2026年高县水上乐园重磅开业:皮划艇比赛、无动力乐园、端午狂欢节全攻略 - 年度推荐企业名录
  • 信号分解算法选型指南:从EMD到VMD,如何根据你的数据特征避开模态混叠?
  • 屏蔽多云差异:多云底座的架构设计与实践
  • JUC 概述
  • logo设计大赛/服务明星评选微信投票小程序怎么做?这5个坑90%的人都在踩|众星评选避坑指南 - 微信投票小程序
  • 2026年6月拖地机厂家推荐排行榜:手推式/驾驶式/自走式/电瓶式拖地机,全自动拖地车源头厂家深度解析 - 企业推荐官【官方】
  • 下水管道爬行检测机器人品牌推荐 - 资讯焦点
  • 温州洞头区商圈实测:当前金价与回收避坑指南 - 专业黄金回收