自定义组件—基于TimePIcker或DatePicker实现时间或日期选择组件 原创
1. 效果演示
日期选择组件实现
时间选择组件实现
2. 引言
在项目开发中遇到需要时间或日期的组件,于是查阅文档,发现了DatePickerDialog/TimePickerDialog两个选择器弹窗,然而在实际的使用过程中发现他们不是太好使用,且只能是弹窗的形式。于是再次查阅文档发现TimePicker和DatePicker选择组件于是在此基础上再次自定义样式,实现符合自己需求的选择器样式。
本文将深入探讨如何自定义基于TimePicker和DatePicker的组件,以满足不同场景下的需求。通过这两个组件,开发者可以实现灵活的时间和日期选择功能,使得用户操作更加便捷和高效。
3. 组件概述
在本节中,我们将对TimePickerComponents和DatePickerComponents这两个自定义组件进行概述,了解它们的功能、结构以及在实际项目中的应用场景。
3.1 TimePickerComponents
TimePickerComponents是一个用于选择时间的组件,主要功能是允许用户设定出发时间。这一组件设计得非常简洁,用户可以轻松地选择所需的时间,然后通过“确定”或“取消”按钮进行确认或放弃选择。
主要特性:
- 时间选择:用户能够以小时和分钟为单位选择时间,采用24小时制的显示方式。
- 样式定制:组件支持自定义样式,包括文本颜色、字体大小、按钮样式等,以符合整体应用的设计风格。
- 回调函数:组件提供confirm和closeBox两个回调函数,分别用于处理用户确认选定时间和关闭组件的操作。
3.2 DatePickerComponents
DatePickerComponents是用于选择日期的组件,专为方便用户设定旅行日期而设计。通过一个直观的界面,用户可以选择起始和结束日期,从而进行个性化的行程安排。
主要特性:
- 样式定制:同样支持自定义样式,帮助开发者调整组件外观,以适应不同的UI设计。
- 日期变化监听:通过.onDateChange事件,组件能够实时监控用户选择的日期,并立即更新内部状态。
这两个组件不仅功能强大,而且它们的实现逻辑清晰,使得开发者可以轻松集成到现有的项目中。在接下来的部分,我们将对TimePickerComponents进行详细解析,分析其结构、属性和交互设计,帮助开发者更好地理解其内部工作原理。
4. TimePickerComponents 详解
先直接给出示例代码
@Entry
@Component
export struct TimePickerComponents {
private selectedTime: Date = new Date('2025-12-10T08:30:00')
confirm: ((time: Date) => void) | undefined = undefined
closeBox: (() => void)| undefined = undefined
build() {
Column() {
Text("设置出发时间")
.fontColor(Color.Black)
.fontSize(16)
.width("100%")
.height('10%')
.padding({left: 11, top: 6})
Column(){
TimePicker({
selected: this.selectedTime,
format: TimePickerFormat.HOUR_MINUTE,
})
.useMilitaryTime(true)
.onChange((value: TimePickerResult) => {
if(value.hour >= 0) {
this.selectedTime.setHours(value.hour, value.minute)
console.info('select current date is: ' + JSON.stringify(value))
}
})
.disappearTextStyle({color: "#F6F6F6", font: {size: 18, weight: FontWeight.Lighter}})
.textStyle({color: "#858585", font: {size: 18, weight: FontWeight.Normal}})
.selectedTextStyle({color: "#000000", font: {size: 18}})
.width("76%")
.height("74%")
Row(){
Button("取消", { type: ButtonType.Normal })
.margin({left: 30})
.backgroundColor($r("app.color.cancel_background2"))
.fontColor($r("app.color.font_color"))
.fontSize(18)
.borderRadius(5)
.height(34)
.width('33%')
.onClick(() => {
if(this.closeBox){
this.closeBox()
}
})
Button("确定", { type: ButtonType.Normal})
.margin({right: 30})
.fontColor($r("app.color.confirm_font"))
.linearGradient({
direction: GradientDirection.Left,
colors: [[$r("app.color.confirm_background1"), 0.0], [$r("app.color.confirm_background2"), 1.0]]
})
.fontSize(18)
.borderRadius(5)
.height(34)
.width('33%')
.onClick(() => {
if(this.confirm){
this.confirm(this.selectedTime);
}
})
}
.defaultFocus(true)
.height("26%")
.width("100%")
.justifyContent(FlexAlign.SpaceBetween)
}
.height("50%")
.width("100%")
.alignItems(HorizontalAlign.Center)
}
.width('100%')
.height('100%')
.backgroundColor($r("app.color.plan_item_background"))
}
}
属性方面有
- selectedTime:这个私有属性用于存储用户当前选择的时间,初始化为一个特定的日期和时间(如2025-12-10T08:30:00)。在组件创建时,该时间用于填充时间选择器。
- confirm和closeBox:这两个属性分别为回调函数,用户可以在点击“确定”或“取消”按钮时调用它们。这允许父组件实现对所选时间的处理或关闭时间选择器的功能。
4.1 时间选择的实现
TimePicker({
selected: this.selectedTime,
format: TimePickerFormat.HOUR_MINUTE,
})
.useMilitaryTime(true)
.onChange((value: TimePickerResult) => {
if (value.hour >= 0) {
this.selectedTime.setHours(value.hour, value.minute);
console.info('select current date is: ' + JSON.stringify(value));
}
})
- 时间选择器配置:通过传入selected属性,时间选择器知道当前选定的时间是什么;format定义了时间的显示格式。
- 时间格式:调用.useMilitaryTime(true)使得时间选择器以24小时制显示时间。
- 时间变更监听:.onChange事件监听用户在时间选择器中的选择,当用户选择新的时间时,这个事件将被触发。我们使用setHours方法来更新selectedTime属性,以确保每次选择后组件状态的一致性。
4.2 交互设计
Row() {
Button("取消", { type: ButtonType.Normal })
.onClick(() => {
if (this.closeBox) {
this.closeBox();
}
});
Button("确定", { type: ButtonType.Normal })
.onClick(() => {
if (this.confirm) {
this.confirm(this.selectedTime);
}
});
}
按钮具体样式实现看前面的具体代码
- “取消”按钮:当用户点击此按钮时,调用closeBox回调函数,允许父组件处理关闭操作。这对用户非常友好,允许他们轻松返回而不必进行选择。
- “确定”按钮:此按钮在用户点击后会调用confirm回调,传递当前选择的时间。这一机制使得父组件能够接收并处理所选时间,可以进行后续的业务逻辑处理,例如保存到数据库或用于界面更新。
4.3 TimePicker属性介绍
这里只介绍一些最新的属性供大家使用
- disappearTextStyle10+ 设置所有选项中最上和最下两个选项的文本颜色、字号、字体粗细。
- textStyle10+ 设置所有选项中除了最上、最下及选中项以外的文本颜色、字号、字体粗细。
- selectedTextStyle10+ 设置选中项的文本颜色、字号、字体粗细。
- loop11+ 设置是否启用循环模式。
- dateTimeOptions12+ 设置时分秒是否显示前置0。
5. DatePickerComponents 详解
DatePicker组件和上面的TimePicker并未太大差别,这里介绍一下实现和属性。
5.1 日期选择的实现
DatePicker({
start: new Date('1970-1-1'),
end: new Date('2100-1-1'),
selected: this.selectedDate
})
.disappearTextStyle({color: "#F6F6F6", font: {size: 18, weight: FontWeight.Lighter}})
.textStyle({color: "#858585", font: {size: 18, weight: FontWeight.Normal}})
.selectedTextStyle({color: "#000000", font: {size: 18}})
.lunar(false)
.width("76%")
.height("74%")
.onDateChange((value: Date) => {
this.selectedDate = value
})
- 日期选择器配置:start和end属性定义了日期选择的范围,这里的范围覆盖了从1970年到2100年的所有日期,确保了用户选择的灵活性。selected属性指定了当前选定的日期。
- 日期变化监听:通过.onDateChange事件来监听用户的日期选择并更新selectedDate属性。当用户选择新的日期时,系统会自动更新该属性,以保持状态的一致性。
5.2 DatePicker属性介绍
- lunar 设置弹窗的日期是否显示农历。
- disappearTextStyle10+ 设置所有选项中最上和最下两个选项的文本样式。
- textStyle10+ 设置所有选项中除了最上、最下及选中项以外的文本样式。
- selectedTextStyle10+ 设置选中项的文本样式。
6. 使用示例
这里我以时间组件的使用为例
具体示例:自定义弹窗
@CustomDialog
struct TimpickerDialog{
@Link dayPlayPlaces: Array<Array<PlayPlace>>;
@Link selectDayBtn: number;
@Link idCityTitleModel: IdCityTitleModel;
@Link timeCnt: Array<string>;
controller: CustomDialogController;
build() {
TimePickerComponents({
confirm: async (time: Date) => {
console.log("===选择出发时间" + time.toString());
let temp = this.dayPlayPlaces[this.selectDayBtn];
let timeString = `${time.getHours() > 9 ? time.getHours() : "0" + time.getHours()}:${time.getMinutes() > 9 ? time.getMinutes() : "0" + time.getMinutes()}`;
console.log("===" + await updateStartTime(this.idCityTitleModel.routeId, timeString, this.selectDayBtn + 1));
this.timeCnt = await arrivalTime(this.idCityTitleModel.routeId, this.selectDayBtn + 1);
temp.forEach((_, idx) => { temp[idx].time = timeString; });
this.dayPlayPlaces.splice(this.selectDayBtn, 1, temp);
this.controller.close();
},
closeBox: () => { this.controller.close(); }
})
}
}
// 调用弹窗的示例
Text(this.dayPlayPlaces[this.selectDayBtn][0].time)
.fontSize(16)
.fontColor($r("app.color.time"))
.margin({ left: 8.76 })
.onClick((event: ClickEvent) => {
this.offSetX = event.windowX - 90;
this.offSetY = event.windowY - 555;
if (this.offSetY >= 25) this.offSetY -= 270;
this.dialogController = new CustomDialogController({
builder: CustomDialogExample({
dayPlayPlaces: this.dayPlayPlaces,
selectDayBtn: this.selectDayBtn,
idCityTitleModel: this.idCityTitleModel,
timeCnt: this.timeCnt
}),
cancel: () => {},
autoCancel: true,
onWillDismiss: (dismissDialogAction: DismissDialogAction) => {
console.info("reason=" + JSON.stringify(dismissDialogAction.reason));
console.log("dialog onWillDismiss");
if (dismissDialogAction.reason == DismissReason.PRESS_BACK || dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
dismissDialogAction.dismiss();
}
},
alignment: DialogAlignment.Bottom,
offset: { dx: this.isFullScreen ? 0 : this.offSetX, dy: this.isFullScreen ? -23 : this.offSetY },
gridCount: 4,
customStyle: false,
cornerRadius: 10,
width: 255,
height: 240,
});
if (this.dialogController != null) {
this.dialogController.open();
}
})
- TimepickerDialog 结构
该结构实现了TimePickerComponents,并为用户选择时间提供了交互界面。用户选择确认后,时间会更新到对应的dayPlayPlaces项中。 - 时间文本点击事件:
通过点击动态生成的时间文本以打开弹窗,用户可以在其中选择出发时间。这里采用了点击事件,能根据用户当前位置调整弹窗显示位置。这个弹窗显示位置跟随主弹窗,可以看团队另外一篇博客。OpenHarmony之跟随弹窗CustomDialog(详细代码实现+运行实例 - 对话框的管理:
通过CustomDialogController,您可以灵活控制对话框的打开、关闭,以及关闭时的各种处理。此设计确保用户拥有良好的交互体验。
当然也可以使用封装成半模态弹窗,关于半模态弹窗的实现,可以看我的这一篇文章ArkUI框架下半模态弹窗的自定义设计指南:打造丝滑的用户体验 在这篇文章就只介绍自定义弹窗的实现了。
7. 总结
在本文中,我们详细探讨了如何使用自定义组件TimePickerComponents与DatePickerComponents来实现时间和日期选择功能。通过分析代码结构、交互设计以及样式设置,我们展示了如何将这些组件灵活地应用到实际项目中,以提升用户体验。最后恳请大家点赞。互相学习分析。