介绍

本篇Codelab将介绍如何使用弹窗功能,实现四种类型弹窗。分别是:警告弹窗、自定义弹窗、日期滑动选择器弹窗、文本滑动选择器弹窗。需要完成以下功能:
- 点击左上角返回按钮展示警告弹窗。
- 点击出生日期展示日期滑动选择器弹窗。
- 点击性别展示文本滑动选择器弹窗。
- 点击兴趣爱好(多选)展示自定义弹窗。
相关概念
- 警告弹窗:显示警告弹窗组件,可设置文本内容与响应回调。
- 自定义弹窗: 通过CustomDialogController类显示自定义弹窗。
- 日期滑动选择器弹窗:根据指定范围的Date创建可以选择日期的滑动选择器,展示在弹窗上。
- 文本滑动选择器弹窗:根据指定的选择范围创建文本选择器,展示在弹窗上。
完整示例
gitee源码地址
源码下载
构建多种样式弹窗(ArkTS).zip
代码结构解读
本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在源码下载或gitee中提供。
├──entry/src/main/ets // 代码区
│ ├──common
│ │ ├──constants
│ │ │ └──CommonConstants.ets // 常量类
│ │ └──utils
│ │ ├──CommonUtils.ets // 弹窗操作工具类
│ │ └──Logger.ets // 日志打印工具类
│ ├──entryability
│ │ └──EntryAbility.ets // 程序入口类
│ ├──pages
│ │ └──HomePage.ets // 主页面
│ ├──view
│ │ ├──CustomDialogWidget.ets // 自定义弹窗组件
│ │ ├──TextCommonWidget.ets // 自定义Text组件
│ │ └──TextInputWidget.ets // 自定义TextInput组件
│ └──viewmodel
│ └──HobbyItem.ets // 兴趣爱好类
└──entry/src/main/resources // 资源文件目录
构建主页面
应用主页面采用Column容器嵌套自定义组件形式完成页面整体布局,效果如图所示:

从上面效果图可以看出,主界面由2个相同样式的文本输入框和3个相同样式的文本布局组成。我们可以将文本输入框抽取成TextInputWidget子组件。再将文本布局抽取成TextCommonWidget子组件。
在ets目录下,点击鼠标右键 > New > Directory,新建名为view的自定义子组件目录。然后在view目录下,点击鼠标右键 > New > ArkTS File,新建两个ArkTS文件,分别为TextInputWidget子组件、TextCommonWidget子组件。
文本输入框抽取成TextInputWidget子组件,效果如图所示:

// TextInputWidget.ets
@Component
export default struct TextInputWidget {// 文本框左侧图片private inputImage?: Resource; // 文本框提示private hintText?: Resource;build() {Row() {Image(this.inputImage !== undefined ? this.inputImage : '')...TextInput({ placeholder: this.hintText })...}...}
}
文本布局抽取成TextCommonWidget子组件,效果如图所示:

// TextCommonWidget.ets
@Component
export default struct TextCommonWidget {// 显示内容@Link content: string;// 文字标题左侧图片private textImage?: Resource;// 文本标题private title?: Resource;// 点击事件回调onItemClick = () => {};build() {Row() {Image(this.textImage !== undefined ? this.textImage : '')...Text(this.title)...Text(this.content)...Image($r('app.media.ic_arrow'))...}.onClick(this.onItemClick)...}
}
在HomePage主界面引用TextInputWidget和TextCommonWidget子组件,然后初始化出生日期、性别、兴趣爱好默认数据。
// HomePage.ets
@Entry
@Component
struct HomePage {@State birthdate: string = '';@State sex: string = '';@State hobbies: string = '';...build() {Column() {...TextInputWidget({inputImage: $r('app.media.ic_nickname'),hintText: $r('app.string.text_input_hint')})TextCommonWidget({textImage: $r('app.media.ic_birthdate'),title: $r('app.string.title_birthdate'),content: $birthdate,onItemClick: () => {CommonUtils.datePickerDialog((birthValue: string) => {this.birthdate = birthValue;});}})TextCommonWidget({textImage: $r('app.media.ic_sex'),title: $r('app.string.title_sex'),content: $sex,onItemClick: () => {CommonUtils.textPickerDialog(this.sexArray, (sexValue: string) => {this.sex = sexValue;});}})TextInputWidget({inputImage: $r('app.media.ic_signature'),hintText: $r('app.string.text_input_signature')})TextCommonWidget({textImage: $r('app.media.ic_hobbies'),title: $r('app.string.title_hobbies'),content: $hobbies,onItemClick: () => {this.customDialogController.open();}})}...}
}
警告弹窗
点击主页面左上角返回按钮,通过CommonUtils.alertDialog方法弹出警告弹窗,提醒用户是否进行当前操作,效果如图所示:

// CommonUtils.ets
alertDialog(context: Context.UIAbilityContext) {AlertDialog.show({// 提示信息message: $r('app.string.alert_dialog_message'), // 弹窗显示位置alignment: DialogAlignment.Bottom,// 弹窗偏移位置offset: {dx: 0,dy: CommonConstants.DY_OFFSET},primaryButton: {value: $r('app.string.cancel_button'),action: () => {...}},secondaryButton: {value: $r('app.string.definite_button'),action: () => {// 退出应用context.terminateSelf();...}}});
}
日期滑动选择器弹窗
点击出生日期选项,通过CommonUtils.datePickerDialog方法弹出日期选择器弹窗,根据需要选择相应时间,效果如图所示:

// CommonUtils.ets
datePickerDialog(dateCallback: Function) {DatePickerDialog.show({// 开始时间start: new Date(CommonConstants.START_TIME),// 结束时间end: new Date(), // 当前选中时间selected: new Date(CommonConstants.SELECT_TIME),// 是否显示农历lunar: false,onAccept: (value: DatePickerResult) => {let year: number = Number(value.year);let month: number = Number(value.month) + CommonConstants.PLUS_ONE;let day: number = Number(value.day);let birthdate: string = this.getBirthDateValue(year, month, day);dateCallback(birthdate);}});
}// 获取出生日期值
getBirthDateValue(year: number, month: number, day: number): string {let birthdate: string = `${year}${CommonConstants.DATE_YEAR}${month}` +`${CommonConstants.DATE_MONTH}${day}${CommonConstants.DATE_DAY}`;return birthdate;
}// HomePage.ets
build() {Column() {...TextCommonWidget({textImage: $r('app.media.ic_birthdate'),title: $r('app.string.title_birthdate'),content: $birthdate,onItemClick: () => {CommonUtils.datePickerDialog((birthValue: string) => {this.birthdate = birthValue;});}})...}...
}
文本滑动选择器弹窗
点击性别选项,通过CommonUtils.textPickerDialog方法弹出性别选择器弹窗,根据需要选择相应性别,效果如图所示:

// CommonUtils.ets
textPickerDialog(sexArray: Resource, sexCallback: Function) {...TextPickerDialog.show({range: sexArray,selected: 0,onAccept: (result: TextPickerResult) => {sexCallback(result.value);},onCancel: () => {...}});
}// HomePage.ets
build() {Column() {...TextCommonWidget({textImage: $r('app.media.ic_sex'),title: $r('app.string.title_sex'),content: $sex,onItemClick: () => {CommonUtils.textPickerDialog(this.sexArray, (sexValue: string) => {this.sex = sexValue;});}})...}...
}
自定义弹窗
点击兴趣爱好选项,通过customDialogController.open方法弹出自定义弹窗,根据需要选择相应的兴趣爱好,效果如图所示:

在view目录下,点击鼠标右键 > New > ArkTS File,新建一个ArkTS文件,然后命名为CustomDialogWidget子组件。
在CustomDialogWidget的aboutToAppear方法,通过manager.getStringArrayValue方法获取本地资源数据进行初始化。
// CustomDialogWidget.ets
@State hobbyItems: HobbyItem[] = [];
...
aboutToAppear() {let context: Context = getContext(this);if (CommonUtils.isEmpty(context) || CommonUtils.isEmpty(context.resourceManager)) {Logger.error(CommonConstants.TAG_CUSTOM, 'context or resourceManager is null');return;}let manager = context.resourceManager;manager.getStringArrayValue($r('app.strarray.hobbies_data').id, (error, hobbyArray) => {if (!CommonUtils.isEmpty(error)) {Logger.error(CommonConstants.TAG_CUSTOM, 'error = ' + JSON.stringify(error));} else {hobbyArray.forEach((hobby: string) => {let hobbyItem = new HobbyItem();hobbyItem.label = hobby;hobbyItem.isChecked = false;this.hobbyItems.push(hobbyItem);});}});
}
当用户点击确定按钮时,通过setHobbiesValue方法处理自定义弹窗选项结果。
// CustomDialogWidget.ets
@State hobbyItems: HobbyItem[] = [];
@Link hobbies: string;
private controller?: CustomDialogController;// 处理自定义弹窗选项结果
setHobbiesValue(hobbyItems: HobbyItem[]) {if (CommonUtils.isEmptyArr(hobbyItems)) {Logger.error(CommonConstants.TAG_HOME, 'hobbyItems length is 0');return;}let hobbiesText: string = '';hobbiesText = hobbyItems.filter((isCheckItem: HobbyItem) => isCheckItem?.isChecked).map<string>((checkedItem: HobbyItem) => {return checkedItem.label!;}).join(CommonConstants.COMMA);if (hobbiesText.length > 0) {this.hobbies = hobbiesText;}
}build() {Column() {...Row() {Button($r('app.string.cancel_button')).dialogButtonStyle().onClick(() => {this.controller?.close();})Blank()...Button($r('app.string.definite_button')).dialogButtonStyle().onClick(() => {this.setHobbiesValue(this.hobbyItems);this.controller?.close();})}}...
}@Extend(Button) function dialogButtonStyle() {....
}
通过@Link修饰的hobbies把值赋给HomePage的hobbies,然后hobbies刷新显示内容。
// HomePage.ets
@State hobbies: string = '';
customDialogController: CustomDialogController = new CustomDialogController({builder: CustomDialogWidget({hobbies: $hobbies}),alignment: DialogAlignment.Bottom,customStyle: true,offset: {dx: 0,dy: CommonConstants.DY_OFFSET}
});build() {Column() {...TextCommonWidget({textImage: $r('app.media.ic_hobbies'),title: $r('app.string.title_hobbies'),content: $hobbies,onItemClick: () => {// 打开自定义弹窗this.customDialogController.open();}})}...
}
总结
您已经完成了本次Codelab的学习,并了解到以下知识点:
- 使用CustomDialogController实现自定义弹窗。
- 使用AlertDialog实现警告弹窗。
- 使用DatePickerDialog实现日期滑动选择弹窗。
- 使用TextPickerDialog实现文本滑动选择弹窗。