本篇学习各种弹窗组件实现年俗弹窗与倒计时关闭图弹窗与对话框设计 的关键流程与实现要点。学习目标完成本篇后你将能够✅ 使用系统弹窗组件✅ 创建自定义弹窗✅ 实现弹窗动画效果✅ 开发年俗弹窗功能预计学习时间约 90 分钟实战一系统弹窗组件第一步AlertDialog 警告弹窗Entry Component struct Lesson21Page { showAlertDialog() { AlertDialog.show({ title: 提示, message: 确定要退出吗, autoCancel: true, alignment: DialogAlignment.Center, primaryButton: { value: 取消, action: () { console.log(点击取消); } }, secondaryButton: { value: 确定, fontColor: #c41e3a, action: () { console.log(点击确定); } } }); } build() { Column() { Button(显示警告弹窗) .onClick(() { this.showAlertDialog(); }) } } }第二步ActionSheet 操作面板showActionSheet() { ActionSheet.show({ title: 选择朝代, message: 请选择要查看的朝代, autoCancel: true, sheets: [ { title: 秦朝, action: () console.log(秦) }, { title: 汉朝, action: () console.log(汉) }, { title: 唐朝, action: () console.log(唐) }, { title: 宋朝, action: () console.log(宋) }, { title: 明朝, action: () console.log(明) }, { title: 清朝, action: () console.log(清) } ] }); }第三步DatePickerDialog 日期选择showDatePicker() { DatePickerDialog.show({ start: new Date(2020-1-1), end: new Date(2030-12-31), selected: new Date(), lunar: true, // 显示农历 onAccept: (value: DatePickerResult) { console.log(选择日期: ${value.year}-${value.month}-${value.day}); } }); }第四步TextPickerDialog 文本选择showTextPicker() { TextPickerDialog.show({ range: [秦朝, 汉朝, 唐朝, 宋朝, 明朝, 清朝], selected: 0, onAccept: (value: TextPickerResult) { console.log(选择: ${value.value}); } }); }实战二自定义弹窗第一步创建自定义弹窗组件CustomDialog struct CustomAlertDialog { controller: CustomDialogController; title: string ; message: string ; onConfirm: () void () {}; build() { Column({ space: 16 }) { Text(this.title) .fontSize(18) .fontWeight(FontWeight.Bold) .fontColor(#1e293b) Text(this.message) .fontSize(14) .fontColor(#64748b) .textAlign(TextAlign.Center) Row({ space: 12 }) { Button(取消) .layoutWeight(1) .backgroundColor(#f0f0f0) .fontColor(#1e293b) .onClick(() { this.controller.close(); }) Button(确定) .layoutWeight(1) .backgroundColor(#c41e3a) .onClick(() { this.onConfirm(); this.controller.close(); }) } .width(100%) } .width(80%) .padding(24) .backgroundColor(Color.White) .borderRadius(16) } }第二步使用自定义弹窗Entry Component struct Lesson21Page { private dialogController: CustomDialogController new CustomDialogController({ builder: CustomAlertDialog({ title: 自定义弹窗, message: 这是一个自定义弹窗示例, onConfirm: () { console.log(确认); } }), autoCancel: true, alignment: DialogAlignment.Center, customStyle: true }); build() { Column() { Button(显示自定义弹窗) .onClick(() { this.dialogController.open(); }) } } }第三步弹窗配置选项选项说明autoCancel点击遮罩是否关闭alignment弹窗位置customStyle使用自定义样式offset位置偏移gridCount弹窗宽度栅格数实战三弹窗动画效果第一步入场动画CustomDialog struct AnimatedDialog { controller: CustomDialogController; State scale: number 0.8; State opacity: number 0; aboutToAppear() { animateTo({ duration: 300, curve: Curve.EaseOut }, () { this.scale 1; this.opacity 1; }); } build() { Column() { Text(动画弹窗) .fontSize(18) .fontColor(#1e293b) } .width(80%) .padding(24) .backgroundColor(Color.White) .borderRadius(16) .scale({ x: this.scale, y: this.scale }) .opacity(this.opacity) } }第二步关闭动画CustomDialog struct AnimatedDialog { controller: CustomDialogController; State scale: number 1; State opacity: number 1; closeWithAnimation() { animateTo({ duration: 200, curve: Curve.EaseIn, onFinish: () { this.controller.close(); } }, () { this.scale 0.8; this.opacity 0; }); } build() { Column({ space: 16 }) { Text(动画弹窗) .fontSize(18) .fontColor(#1e293b) Button(关闭) .onClick(() { this.closeWithAnimation(); }) } .width(80%) .padding(24) .backgroundColor(Color.White) .borderRadius(16) .scale({ x: this.scale, y: this.scale }) .opacity(this.opacity) } }实战四年俗弹窗实现第一步创建年俗弹窗组件interface YearCustomInfo { name: string; description: string; lunarDate: string; } CustomDialog struct YearCustomDialog { controller: CustomDialogController; customInfo: YearCustomInfo { name: , description: , lunarDate: }; State countdown: number 3; State scale: number 0.8; State opacity: number 0; private timerId: number -1; aboutToAppear() { // 入场动画 animateTo({ duration: 300, curve: Curve.EaseOut }, () { this.scale 1; this.opacity 1; }); // 倒计时 this.startCountdown(); } aboutToDisappear() { if (this.timerId ! -1) { clearInterval(this.timerId); } } startCountdown() { this.timerId setInterval(() { this.countdown--; if (this.countdown 0) { clearInterval(this.timerId); this.closeWithAnimation(); } }, 1000); } closeWithAnimation() { animateTo({ duration: 200, curve: Curve.EaseIn, onFinish: () { this.controller.close(); } }, () { this.scale 0.8; this.opacity 0; }); } build() { Column({ space: 16 }) { // 农历日期 Text(this.customInfo.lunarDate) .fontSize(14) .fontColor(#64748b) // 年俗名称 Text(this.customInfo.name) .fontSize(28) .fontWeight(FontWeight.Bold) .fontColor(#c41e3a) // 描述 Text(this.customInfo.description) .fontSize(14) .fontColor(#64748b) .textAlign(TextAlign.Center) // 倒计时 Text(${this.countdown}秒后自动关闭) .fontSize(12) .fontColor(#9ca3af) .margin({ top: 8 }) // 关闭按钮 Button(知道了) .width(100%) .backgroundColor(#c41e3a) .margin({ top: 8 }) .onClick(() { if (this.timerId ! -1) { clearInterval(this.timerId); } this.closeWithAnimation(); }) } .width(80%) .padding(24) .backgroundColor(Color.White) .borderRadius(16) .scale({ x: this.scale, y: this.scale }) .opacity(this.opacity) } }第二步在页面中使用Entry Component struct Lesson21Page { State showYearCustom: boolean false; private yearCustomDialogController: CustomDialogController new CustomDialogController({ builder: YearCustomDialog({ customInfo: { name: 贴春联, description: 贴对联、门神迎接新年, lunarDate: 腊月廿九 } }), autoCancel: false, alignment: DialogAlignment.Center, customStyle: true }); aboutToAppear() { // 检查是否需要显示年俗弹窗 this.checkYearCustom(); } checkYearCustom() { // 模拟如果是年俗日期显示弹窗 setTimeout(() { this.yearCustomDialogController.open(); }, 1000); } build() { Column({ space: 20 }) { // 头部 Row() { Text(弹窗与对话框) .fontSize(18) .fontWeight(FontWeight.Bold) .fontColor(#1e293b) } .width(100%) .height(56) .padding({ left: 16, right: 16 }) .backgroundColor(Color.White) // 按钮列表 Column({ space: 12 }) { Button(警告弹窗) .width(100%) .onClick(() { this.showAlertDialog(); }) Button(操作面板) .width(100%) .onClick(() { this.showActionSheet(); }) Button(日期选择) .width(100%) .onClick(() { this.showDatePicker(); }) Button(年俗弹窗) .width(100%) .backgroundColor(#c41e3a) .onClick(() { this.yearCustomDialogController.open(); }) } .width(100%) .padding(16) } .width(100%) .height(100%) .backgroundColor(#f8f6f5) } showAlertDialog() { AlertDialog.show({ title: 提示, message: 这是一个警告弹窗, primaryButton: { value: 确定, action: () {} } }); } showActionSheet() { ActionSheet.show({ title: 选择操作, sheets: [ { title: 选项一, action: () {} }, { title: 选项二, action: () {} }, { title: 选项三, action: () {} } ] }); } showDatePicker() { DatePickerDialog.show({ selected: new Date(), lunar: true, onAccept: () {} }); } } Builder export function Lesson21PageBuilder() { Lesson21Page() }第三步运行验证hvigorw assembleHap --no-daemon本课小结核心知识点知识点说明AlertDialog警告弹窗ActionSheet操作面板DatePickerDialog日期选择CustomDialog自定义弹窗装饰器CustomDialogController弹窗控制器弹窗最佳实践合理使用系统弹窗自定义弹窗注意动画及时清理定时器处理遮罩点击课后练习练习1实现底部弹出面板创建从底部滑出的弹窗。练习2添加弹窗队列实现多个弹窗依次显示。下一课预告第22课我们将学习图片处理与资源管理包括图片资源类型图片组件配置图片处理能力资源管理器使用项目开源地址https://gitcode.com/daleishen/gujinzhijian
HarmonyOS APP<<古今职鉴定>>开源教程第21篇:弹窗与对话框设计
本篇学习各种弹窗组件实现年俗弹窗与倒计时关闭图弹窗与对话框设计 的关键流程与实现要点。学习目标完成本篇后你将能够✅ 使用系统弹窗组件✅ 创建自定义弹窗✅ 实现弹窗动画效果✅ 开发年俗弹窗功能预计学习时间约 90 分钟实战一系统弹窗组件第一步AlertDialog 警告弹窗Entry Component struct Lesson21Page { showAlertDialog() { AlertDialog.show({ title: 提示, message: 确定要退出吗, autoCancel: true, alignment: DialogAlignment.Center, primaryButton: { value: 取消, action: () { console.log(点击取消); } }, secondaryButton: { value: 确定, fontColor: #c41e3a, action: () { console.log(点击确定); } } }); } build() { Column() { Button(显示警告弹窗) .onClick(() { this.showAlertDialog(); }) } } }第二步ActionSheet 操作面板showActionSheet() { ActionSheet.show({ title: 选择朝代, message: 请选择要查看的朝代, autoCancel: true, sheets: [ { title: 秦朝, action: () console.log(秦) }, { title: 汉朝, action: () console.log(汉) }, { title: 唐朝, action: () console.log(唐) }, { title: 宋朝, action: () console.log(宋) }, { title: 明朝, action: () console.log(明) }, { title: 清朝, action: () console.log(清) } ] }); }第三步DatePickerDialog 日期选择showDatePicker() { DatePickerDialog.show({ start: new Date(2020-1-1), end: new Date(2030-12-31), selected: new Date(), lunar: true, // 显示农历 onAccept: (value: DatePickerResult) { console.log(选择日期: ${value.year}-${value.month}-${value.day}); } }); }第四步TextPickerDialog 文本选择showTextPicker() { TextPickerDialog.show({ range: [秦朝, 汉朝, 唐朝, 宋朝, 明朝, 清朝], selected: 0, onAccept: (value: TextPickerResult) { console.log(选择: ${value.value}); } }); }实战二自定义弹窗第一步创建自定义弹窗组件CustomDialog struct CustomAlertDialog { controller: CustomDialogController; title: string ; message: string ; onConfirm: () void () {}; build() { Column({ space: 16 }) { Text(this.title) .fontSize(18) .fontWeight(FontWeight.Bold) .fontColor(#1e293b) Text(this.message) .fontSize(14) .fontColor(#64748b) .textAlign(TextAlign.Center) Row({ space: 12 }) { Button(取消) .layoutWeight(1) .backgroundColor(#f0f0f0) .fontColor(#1e293b) .onClick(() { this.controller.close(); }) Button(确定) .layoutWeight(1) .backgroundColor(#c41e3a) .onClick(() { this.onConfirm(); this.controller.close(); }) } .width(100%) } .width(80%) .padding(24) .backgroundColor(Color.White) .borderRadius(16) } }第二步使用自定义弹窗Entry Component struct Lesson21Page { private dialogController: CustomDialogController new CustomDialogController({ builder: CustomAlertDialog({ title: 自定义弹窗, message: 这是一个自定义弹窗示例, onConfirm: () { console.log(确认); } }), autoCancel: true, alignment: DialogAlignment.Center, customStyle: true }); build() { Column() { Button(显示自定义弹窗) .onClick(() { this.dialogController.open(); }) } } }第三步弹窗配置选项选项说明autoCancel点击遮罩是否关闭alignment弹窗位置customStyle使用自定义样式offset位置偏移gridCount弹窗宽度栅格数实战三弹窗动画效果第一步入场动画CustomDialog struct AnimatedDialog { controller: CustomDialogController; State scale: number 0.8; State opacity: number 0; aboutToAppear() { animateTo({ duration: 300, curve: Curve.EaseOut }, () { this.scale 1; this.opacity 1; }); } build() { Column() { Text(动画弹窗) .fontSize(18) .fontColor(#1e293b) } .width(80%) .padding(24) .backgroundColor(Color.White) .borderRadius(16) .scale({ x: this.scale, y: this.scale }) .opacity(this.opacity) } }第二步关闭动画CustomDialog struct AnimatedDialog { controller: CustomDialogController; State scale: number 1; State opacity: number 1; closeWithAnimation() { animateTo({ duration: 200, curve: Curve.EaseIn, onFinish: () { this.controller.close(); } }, () { this.scale 0.8; this.opacity 0; }); } build() { Column({ space: 16 }) { Text(动画弹窗) .fontSize(18) .fontColor(#1e293b) Button(关闭) .onClick(() { this.closeWithAnimation(); }) } .width(80%) .padding(24) .backgroundColor(Color.White) .borderRadius(16) .scale({ x: this.scale, y: this.scale }) .opacity(this.opacity) } }实战四年俗弹窗实现第一步创建年俗弹窗组件interface YearCustomInfo { name: string; description: string; lunarDate: string; } CustomDialog struct YearCustomDialog { controller: CustomDialogController; customInfo: YearCustomInfo { name: , description: , lunarDate: }; State countdown: number 3; State scale: number 0.8; State opacity: number 0; private timerId: number -1; aboutToAppear() { // 入场动画 animateTo({ duration: 300, curve: Curve.EaseOut }, () { this.scale 1; this.opacity 1; }); // 倒计时 this.startCountdown(); } aboutToDisappear() { if (this.timerId ! -1) { clearInterval(this.timerId); } } startCountdown() { this.timerId setInterval(() { this.countdown--; if (this.countdown 0) { clearInterval(this.timerId); this.closeWithAnimation(); } }, 1000); } closeWithAnimation() { animateTo({ duration: 200, curve: Curve.EaseIn, onFinish: () { this.controller.close(); } }, () { this.scale 0.8; this.opacity 0; }); } build() { Column({ space: 16 }) { // 农历日期 Text(this.customInfo.lunarDate) .fontSize(14) .fontColor(#64748b) // 年俗名称 Text(this.customInfo.name) .fontSize(28) .fontWeight(FontWeight.Bold) .fontColor(#c41e3a) // 描述 Text(this.customInfo.description) .fontSize(14) .fontColor(#64748b) .textAlign(TextAlign.Center) // 倒计时 Text(${this.countdown}秒后自动关闭) .fontSize(12) .fontColor(#9ca3af) .margin({ top: 8 }) // 关闭按钮 Button(知道了) .width(100%) .backgroundColor(#c41e3a) .margin({ top: 8 }) .onClick(() { if (this.timerId ! -1) { clearInterval(this.timerId); } this.closeWithAnimation(); }) } .width(80%) .padding(24) .backgroundColor(Color.White) .borderRadius(16) .scale({ x: this.scale, y: this.scale }) .opacity(this.opacity) } }第二步在页面中使用Entry Component struct Lesson21Page { State showYearCustom: boolean false; private yearCustomDialogController: CustomDialogController new CustomDialogController({ builder: YearCustomDialog({ customInfo: { name: 贴春联, description: 贴对联、门神迎接新年, lunarDate: 腊月廿九 } }), autoCancel: false, alignment: DialogAlignment.Center, customStyle: true }); aboutToAppear() { // 检查是否需要显示年俗弹窗 this.checkYearCustom(); } checkYearCustom() { // 模拟如果是年俗日期显示弹窗 setTimeout(() { this.yearCustomDialogController.open(); }, 1000); } build() { Column({ space: 20 }) { // 头部 Row() { Text(弹窗与对话框) .fontSize(18) .fontWeight(FontWeight.Bold) .fontColor(#1e293b) } .width(100%) .height(56) .padding({ left: 16, right: 16 }) .backgroundColor(Color.White) // 按钮列表 Column({ space: 12 }) { Button(警告弹窗) .width(100%) .onClick(() { this.showAlertDialog(); }) Button(操作面板) .width(100%) .onClick(() { this.showActionSheet(); }) Button(日期选择) .width(100%) .onClick(() { this.showDatePicker(); }) Button(年俗弹窗) .width(100%) .backgroundColor(#c41e3a) .onClick(() { this.yearCustomDialogController.open(); }) } .width(100%) .padding(16) } .width(100%) .height(100%) .backgroundColor(#f8f6f5) } showAlertDialog() { AlertDialog.show({ title: 提示, message: 这是一个警告弹窗, primaryButton: { value: 确定, action: () {} } }); } showActionSheet() { ActionSheet.show({ title: 选择操作, sheets: [ { title: 选项一, action: () {} }, { title: 选项二, action: () {} }, { title: 选项三, action: () {} } ] }); } showDatePicker() { DatePickerDialog.show({ selected: new Date(), lunar: true, onAccept: () {} }); } } Builder export function Lesson21PageBuilder() { Lesson21Page() }第三步运行验证hvigorw assembleHap --no-daemon本课小结核心知识点知识点说明AlertDialog警告弹窗ActionSheet操作面板DatePickerDialog日期选择CustomDialog自定义弹窗装饰器CustomDialogController弹窗控制器弹窗最佳实践合理使用系统弹窗自定义弹窗注意动画及时清理定时器处理遮罩点击课后练习练习1实现底部弹出面板创建从底部滑出的弹窗。练习2添加弹窗队列实现多个弹窗依次显示。下一课预告第22课我们将学习图片处理与资源管理包括图片资源类型图片组件配置图片处理能力资源管理器使用项目开源地址https://gitcode.com/daleishen/gujinzhijian