【HarmonyOS应用开发】ArkUI 开发框架-进阶篇-应用弹窗(十一)

一、应用弹窗

1、概述

在我们日常使用应用的时候,可能会进行一些敏感的操作,比如删除联系人,这时候我们给应用添加弹窗来提示用户是否需要执行该操作,如下图所示:

弹窗是一种模态窗口,通常用来展示用户当前需要的或用户必须关注的信息或操作。在弹出框消失之前,用户无法操作其他界面内容。ArkUI为我们提供了丰富的弹窗功能,弹窗按照功能可以分为以下两类:

  • 确认类:例如警告弹窗AlertDialog
  • 选择类:包括文本选择弹窗TextPickerDialog 、日期滑动选择弹窗DatePickerDialog、时间滑动选择弹窗TimePickerDialog等。

您可以根据业务场景,选择不同类型的弹窗。部分弹窗效果图如下:

此外,如果上述弹窗还不能满足您的需求,或者需要对弹窗的布局和样式进行自定义,您还可以使用自定义弹窗CustomDialog

下文将分别介绍AlertDialog 、TextPickerDialog 、DatePickerDialog以及CustomDialog的使用。

2、警告弹窗

警告弹窗AlertDialog由以下三部分区域构成,对应下面的示意图:

1、标题区:为可选的。

2、内容区:显示提示消息。

3、操作按钮区:用户做"确认"或者"取消"等操作。

以下示例代码,演示了如何使用AlertDialog 实现上图所示的警告弹窗。AlertDialog可以设置两个操作按钮,示例代码中分别使用primaryButtonsecondaryButton实现了"取消"和"删除"操作按钮,操作按钮可以通过action响应点击事件。

js 复制代码
Button('点击显示弹窗')
	.onClick(() => {
		AlertDialog.show(
			{
				title: '删除联系人', // 标题
				message: '是否需要删除所选联系人?', // 内容
				autoCancel: false, // 点击遮障层时,是否关闭弹窗。
				alignment: DialogAlignment.Bottom, // 弹窗在竖直方向的对齐方式
				offset: { dx: 0, dy: -20 }, // 弹窗相对alignment位置的偏移量
				primaryButton: {
					value: '取消',
					action: () => {
						console.info('Callback when the first button is clicked');
					}
				},
				secondaryButton: {
					value: '删除',
					fontColor: '#D94838',
					action: () => {
						console.info('Callback when the second button is clicked');
					}
				},
				cancel: () => { // 点击遮障层关闭dialog时的回调
					console.info('Closed callbacks');
				}
			}
		)
	})

此外,您还可以使用AlertDialog,构建只包含一个操作按钮的确认弹窗,使用confirm响应操作按钮回调。

js 复制代码
AlertDialog.show(
	{
		title: '提示',
		message: '提示信息',
		autoCancel: true,
		alignment: DialogAlignment.Bottom,
		offset: { dx: 0, dy: -20 },
		confirm: {
			value: '确认',
			action: () => {
				console.info('Callback when confirm button is clicked');
			}
		},
		cancel: () => {
			console.info('Closed callbacks')
		}
	}
)

3、选择类弹窗

选择类弹窗用于方便用户选择相关数据,比如选择喜欢吃的水果、出生日期等等。下面我们以TextPickerDialogDatePickerDialog为例,来介绍选择类弹窗的使用。

3.1、文本选择弹窗

TextPickerDialog为文本滑动选择器弹窗,根据指定的选择范围创建文本选择器,展示在弹窗上,例如下面这段示例代码使用TextPickerDialog实现了一个水果选择弹窗。示例代码中使用selected指定了弹窗的初始选择项索引为2,对应的数据为"香蕉"。当用户点击"确定"操作按钮后,会触发onAccept事件回调,在回调中将选中的值,传递给宿主中的select变量。

js 复制代码
@Entry
@Component
struct TextPickerDialogDemo {
	@State select: number = 2;
	private fruits: string[] = ['苹果', '橘子', '香蕉', '猕猴桃', '西瓜'];

	build() {
		Column() {
			Button('TextPickerDialog')
				.margin(20)
				.onClick(() => {
					TextPickerDialog.show({
						range: this.fruits, // 设置文本选择器的选择范围
						selected: this.select, // 设置初始选中项的索引值。
						onAccept: (value: TextPickerResult) => { // 点击弹窗中的"确定"按钮时触发该回调。
						// 设置select为按下确定按钮时候的选中项index,这样当弹窗再次弹出时显示选中的是上一次确定的选项
						this.select = value.index;
						console.info("TextPickerDialog:onAccept()" + JSON.stringify(value));
					},
					onCancel: () => { // 点击弹窗中的"取消"按钮时触发该回调。
						console.info("TextPickerDialog:onCancel()");
					},
					onChange: (value: TextPickerResult) => { // 滑动弹窗中的选择器使当前选中项改变时触发该回调。
						console.info('TextPickerDialog:onChange()' + JSON.stringify(value));
					}
				})
			})
		}
		.width('100%')
	}
}

效果图如下:

3.2、日期选择弹窗

下面我们介绍另一种常用的选择类弹窗DatePickerDialog,它是日期滑动选择器弹窗,根据指定的日期范围创建日期滑动选择器,展示在弹窗上。DatePickerDialog的使用非常广泛,比如当我们需要输入个人出生日期的时候,就可以使用DatePickerDialog。下面的示例代码实现了一个日期选择弹窗:

js 复制代码
@Entry
@Component
struct DatePickerDialogDemo {
	selectedDate: Date = new Date('2010-1-1');

	build() {
		Column() {
			Button("DatePickerDialog")
				.margin(20)
				.onClick(() => {
					DatePickerDialog.show({
						start: new Date('1900-1-1'), // 设置选择器的起始日期
						end: new Date('2023-12-31'), // 设置选择器的结束日期
						selected: this.selectedDate, // 设置当前选中的日期
						lunar: false,
						onAccept: (value: DatePickerResult) => { // 点击弹窗中的"确定"按钮时触发该回调
							// 通过Date的setFullYear方法设置按下确定按钮时的日期,这样当弹窗再次弹出时显示选中的是上一次确定的日期
							this.selectedDate.setFullYear(value.year, value.month, value.day)
							console.info('DatePickerDialog:onAccept()' + JSON.stringify(value))
						},
						onCancel: () => { // 点击弹窗中的"取消"按钮时触发该回调
							console.info('DatePickerDialog:onCancel()')
						},
						onChange: (value: DatePickerResult) => { // 滑动弹窗中的滑动选择器使当前选中项改变时触发该回调
							console.info('DatePickerDialog:onChange()' + JSON.stringify(value))
						}
					})
				})
		}
		.width('100%')
	}
}

效果图如下:

4、自定义弹窗

自定义弹窗的使用更加灵活,适用于更多的业务场景,在自定义弹窗中您可以自定义弹窗内容,构建更加丰富的弹窗界面。自定义弹窗的界面可以通过装饰器@CustomDialog定义的组件来实现,然后结合CustomDialogController来控制自定义弹窗的显示和隐藏。下面我们通过一个兴趣爱好的选择框来介绍自定义弹窗的使用。

从上面的效果图可以看出,这个选择框是一个多选的列表弹窗,我们可以使用装饰器@CustomDialog,结合List组件来完成这个弹窗布局,实现步骤如下:

初始化弹窗数据。

先准备好资源文件和数据实体类。其中资源文件stringarray.json创建在resources/base/element目录下,文件根节点为strarray

json 复制代码
{
"strarray": [
	{
		"name": "hobbies_data",
		"value": [
			{
				"value": "Soccer"
			},
			{
				"value": "Badminton"
			},
			{
				"value": "Travelling"
			},
			... 
			]
		}
	]
}

实体类HobbyBean用来封装自定义弹窗中的"兴趣爱好"数据。

js 复制代码
export default class HobbyBean {
	label: string;
	isChecked: boolean;
}

1、然后创建一个ArkTS文件CustomDialogWidget,用来封装自定义弹窗,使用装饰器@CustomDialog修饰CustomDialogWidget表示这是一个自定义弹窗。使用资源管理对象manager获取数据,并将数据封装到hobbyBeans

js 复制代码
@CustomDialog
export default struct CustomDialogWidget {
	@State hobbyBeans: HobbyBean[] = [];

	aboutToAppear() {
		let context: Context = getContext(this);
		let manager = context.resourceManager;
		manager.getStringArrayValue($r('app.strarray.hobbies_data'), (error, hobbyResult) => {
			...
			hobbyResult.forEach((hobbyItem: string) => {
				let hobbyBean = new HobbyBean();
				hobbyBean.label = hobbyItem;
				hobbyBean.isChecked = false;
				this.hobbyBeans.push(hobbyBean);
			});
		});
	}

	build() {...}
}

创建弹窗组件。

1、controller对象用于控制弹窗的控制和隐藏,hobbies表示弹窗选中的数据结果。setHobbiesValue方法用于筛选出被选中的数据,赋值给hobbies

js 复制代码
@CustomDialog
export default struct CustomDialogWidget {
	@State hobbyBeans: HobbyBean[] = [];
	@Link hobbies: string;
	private controller?: CustomDialogController;

	aboutToAppear() {...}

	setHobbiesValue(hobbyBeans: HobbyBean[]) {
		let hobbiesText: string = '';
		hobbiesText = hobbyBeans.filter((isCheckItem: HobbyBean) =>
		isCheckItem?.isChecked)
			.map((checkedItem: HobbyBean) => {
				return checkedItem.label;
			}).join(',');
		this.hobbies = hobbiesText;
	}

	build() {
		Column() {
			Text($r('app.string.text_title_hobbies'))...
			List() {
				ForEach(this.hobbyBeans, (itemHobby: HobbyBean) => {
					ListItem() {
						Row() {
							Text(itemHobby.label)...
							Toggle({ type: ToggleType.Checkbox, isOn: false })...
								.onChange((isCheck) => {
									itemHobby.isChecked = isCheck;
								})
						}
					}
				}, itemHobby => itemHobby.label)
			}

			Row() {
				Button($r('app.string.cancel_button'))...
					.onClick(() => {
						this.controller?.close();
					})
				Button($r('app.string.definite_button'))...
					.onClick(() => {
						this.setHobbiesValue(this.hobbyBeans);
						this.controller?.close();
					})
			}
		}
	}
}

使用自定义弹窗。

1、在自定义弹窗的使用页面HomePage中先定义一个变量hobbies,使用装饰器@State修饰,和自定义弹窗中的@Link 装饰器修饰的变量进行双向绑定。然后我们使用alignmentoffset设置弹窗的位置在屏幕底部,并且距离底部20vp。最后我们在自定义组件TextCommonWidget(具体实现可以参考《构建多种样式弹窗》Codelab源码)的点击事件中,调用customDialogControlleropen方法,用于显示弹窗。

js 复制代码
@Entry
@Component
struct HomePage {
	customDialogController: CustomDialogController = new CustomDialogController({
		builder: CustomDialogWidget({
			onConfirm: this.setHobbiesValue.bind(this),
		}),
		alignment: DialogAlignment.Bottom,
		customStyle: true,
		offset: { dx: 0,dy: -20 }
	});

	setHobbiesValue(hobbyArray: HobbyBean[]) {...}

	build() {
		...
			TextCommonWidget({
				...
				title: $r('app.string.title_hobbies'),
				content: $hobby,
				onItemClick: () => {
					this.customDialogController.open();
				}
			})
		...
	}
}

示例代码下载

构建多种样式的弹窗

相关推荐
檀越剑指大厂7 分钟前
【Python系列】异步 Web 服务器
服务器·前端·python
我是Superman丶9 分钟前
【前端】js vue 屏蔽BackSpace键删除键导致页面后退的方法
开发语言·前端·javascript
Hello Dam10 分钟前
基于 Spring Boot 实现图片的服务器本地存储及前端回显
服务器·前端·spring boot
小仓桑12 分钟前
利用 Vue 组合式 API 与 requestAnimationFrame 优化大量元素渲染
前端·javascript·vue.js
Hacker_xingchen12 分钟前
Web 学习笔记 - 网络安全
前端·笔记·学习
天海奈奈13 分钟前
前端应用界面的展示与优化(记录)
前端
多多*34 分钟前
后端并发编程操作简述 Java高并发程序设计 六类并发容器 七种线程池 四种阻塞队列
java·开发语言·前端·数据结构·算法·状态模式
mubeibeinv1 小时前
列表代码思路
前端
过期的H2O21 小时前
【H2O2|全栈】JS进阶知识(十)ES6(6)
开发语言·前端·javascript·ecmascript·es6
ChinaDragonDreamer1 小时前
HarmonyOS:应用沙箱
开发语言·harmonyos·鸿蒙