【HarmonyOS 6】HarmonyOS 自定义时间选择器实现

发布时间:2026/11/4 23:12:05

【HarmonyOS 6】HarmonyOS 自定义时间选择器实现 前言在开发时间管理类应用时时间选择器是一个非常常见的功能。本文将通过近期在鸿蒙应用开发中的一个实际案例详细讲解如何在 HarmonyOS 应用中实现一个自定义的时间选择器。我们这个案例中的选择器支持半小时为单位的时间选择适合用于记录时间块等场景。应用场景在本应用中用户需要记录已经完成的时间块。当用户点击记录时间按钮时会弹出一个对话框让用户选择开始时间和结束时间。注时间选择器支持小时和分钟的独立选择分钟只能选择 00 或 30核心知识点1. CustomDialog 自定义对话框在 HarmonyOS 中CustomDialog装饰器用于创建自定义对话框。与系统提供的标准对话框不同自定义对话框可以完全控制布局和交互逻辑。CustomDialogstruct TimePickerDialogContent{controller:CustomDialogController// 对话框控制器// ... 其他属性和方法}2. CustomDialogController 对话框控制器CustomDialogController用于控制对话框的显示和关闭。在父组件中创建控制器实例然后调用open()方法显示对话框。privatetimePickerController:CustomDialogController|nullnull// 创建并打开对话框this.timePickerControllernewCustomDialogController({builder:TimePickerDialogContent({/* 参数 */}),autoCancel:true,alignment:DialogAlignment.Center})this.timePickerController.open()builder自定义弹窗内容构造器。autoCancel是否允许点击遮障层退出true表示关闭弹窗。false表示不关闭弹窗。alignment弹窗在竖直方向上的对齐方式。3. State 状态管理State装饰器用于声明组件的状态变量。当状态变量的值发生变化时UI 会自动更新。StatetempHour:number0// 临时存储选中的小时StatetempMinute:number0// 临时存储选中的分钟完整实现第一步定义对话框结构首先我们创建一个自定义对话框组件定义它需要的属性CustomDialogstruct TimePickerDialogContent{controller:CustomDialogController// 对话框控制器必需selectedTime:DatenewDate()// 当前选中的时间onConfirm:(hour:number,minute:number)void(){}// 确认回调StatetempHour:number0// 临时小时值StatetempMinute:number0// 临时分钟值// 小时选项0-23privatehours:string[][00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23]// 分钟选项只有 00 和 30privateminutes:string[][00,30]// ... 后续代码}这边我们写的已经很清楚了根据我们的需求小时的选项是完整的从0-23但是分钟的选项只有00和30这是根据我们的需求来设定的。第二步初始化时间值在对话框显示之前我们需要将传入的selectedTime转换为小时和分钟并调整到最近的半小时aboutToAppear():void{// 获取小时0-23this.tempHourthis.selectedTime.getHours()// 将分钟调整为最近的半小时constminutesthis.selectedTime.getMinutes()if(minutes15){// 0-14分钟 → 向下取整到 00this.tempMinute0}elseif(minutes45){// 15-44分钟 → 向上取整到 30this.tempMinute30}else{// 45-59分钟 → 向上取整到下一个小时的 00this.tempHour(this.tempHour1)%24// % 24 确保不超过 23this.tempMinute0}}代码说明aboutToAppear()是组件生命周期方法在组件即将显示时调用我们将任意分钟值调整为 00 或 30这样用户看到的初始值就是半小时对齐的使用% 24确保小时值在 0-23 范围内例如 23 点 50 分会变成 0 点 00 分第三步构建 UI 布局接下来我们使用build()方法构建对话框的 UIbuild(){Column(){// 标题Text(选择时间).fontSize(18).fontWeight(FontWeight.Bold).fontColor($r(app.color.text_primary)).margin({bottom:12})// 提示文字Text(仅支持半小时为单位).fontSize(12).fontColor($r(app.color.text_secondary)).margin({bottom:16})// 时间选择器区域Row(){// 小时选择器Column(){Text(小时).fontSize(12).fontColor($r(app.color.text_secondary)).margin({bottom:8})TextPicker({range:this.hours,// 选项数组selected:this.tempHour// 默认选中项的索引}).onChange((value:string|string[],index:number|number[]){// 当用户滑动选择器时触发if(typeofindexnumber){this.tempHourindex// 更新小时值}})}.layoutWeight(1)// 占据一半宽度// 分隔符Text(:).fontSize(24).fontWeight(FontWeight.Bold).fontColor($r(app.color.text_primary)).margin({left:12,right:12})// 分钟选择器Column(){Text(分钟).fontSize(12).fontColor($r(app.color.text_secondary)).margin({bottom:8})TextPicker({range:this.minutes,selected:this.tempMinute0?0:1// 0分钟→索引030分钟→索引1}).onChange((value:string|string[],index:number|number[]){if(typeofindexnumber){// 将索引转换为实际分钟值this.tempMinuteindex0?0:30}})}.layoutWeight(1)}.width(100%).margin({bottom:16})// 显示当前选中的时间Text(已选择:${this.tempHour.toString().padStart(2,0)}:${this.tempMinute.toString().padStart(2,0)}).fontSize(16).fontWeight(FontWeight.Bold).fontColor($r(app.color.primary_color)).margin({bottom:16})// 按钮区域Row(){// 取消按钮Button(取消).fontSize(15).fontColor($r(app.color.text_secondary)).backgroundColor($r(app.color.input_background)).borderRadius(22).layoutWeight(1).height(44).onClick((){this.controller.close()// 关闭对话框不返回任何值})// 确定按钮Button(确定).fontSize(15).fontColor(Color.White).backgroundColor($r(app.color.primary_color)).borderRadius(22).layoutWeight(1).height(44).margin({left:10}).onClick((){// 调用回调函数将选中的时间传回父组件this.onConfirm(this.tempHour,this.tempMinute)this.controller.close()// 关闭对话框})}.width(100%)}.width(75%)// 对话框宽度为屏幕的 75%.padding(20).backgroundColor($r(app.color.card_background))// 使用主题颜色.borderRadius(16)// 圆角}第四步在父组件中使用现在我们在父组件中创建并打开这个时间选择器Componentexportstruct AddTimeBlockDialog{StatestartTime:DatenewDate()// 开始时间StateendTime:DatenewDate()// 结束时间privatestartTimePickerController:CustomDialogController|nullnull// 格式化时间显示例如14:30privateformatTime(date:Date):string{consthoursdate.getHours().toString().padStart(2,0)constminutesdate.getMinutes().toString().padStart(2,0)return${hours}:${minutes}}// 打开开始时间选择器privateopenStartTimePicker():void{this.startTimePickerControllernewCustomDialogController({builder:TimePickerDialogContent({selectedTime:this.startTime,// 传入当前时间onConfirm:(hour:number,minute:number){// 用户点击确定后更新开始时间constnewTimenewDate(this.startTime)newTime.setHours(hour)newTime.setMinutes(minute)newTime.setSeconds(0)newTime.setMilliseconds(0)this.startTimenewTime// 更新状态UI 会自动刷新}}),autoCancel:true,// 点击对话框外部自动关闭alignment:DialogAlignment.Center,// 居中显示customStyle:true// 使用自定义样式})this.startTimePickerController.open()// 显示对话框}build(){Column(){// 开始时间按钮Button(){Column(){Text(开始).fontSize(11).fontColor($r(app.color.text_secondary))Text(this.formatTime(this.startTime)).fontSize(16).fontWeight(FontWeight.Medium).fontColor($r(app.color.text_primary)).margin({top:2})}}.backgroundColor($r(app.color.input_background)).borderRadius(10).padding(12).onClick((){this.openStartTimePicker()// 点击按钮打开选择器})}}}这边来具体讲一下相关的配置CustomDialogController 配置builder指定对话框的内容组件autoCancel是否允许点击外部关闭alignment对话框在屏幕上的位置customStyle是否使用自定义样式如果为 false会使用系统默认样式回调函数onConfirm是一个箭头函数当用户点击确定时被调用我们在回调中更新startTime状态UI 会自动刷新显示新时间Date 对象操作创建新的 Date 对象new Date(this.startTime)设置小时和分钟setHours()和setMinutes()清零秒和毫秒确保时间精确到分钟总结通过本教程我们学习了如何在 HarmonyOS 中实现一个自定义时间选择器。也通过一个案例知道了如何在实践中实现。这个时间选择器可以直接应用到你的项目中也可以根据需求进行扩展和定制。希望这篇教程对你有所帮助参考资料HarmonyOS 官方文档 - CustomDialogHarmonyOS 官方文档 - TextPicker
延伸阅读

更多相关文章

2026/11/5 2:23:56

Windows系统文件dwmscene.dll丢失找不到问题解决

在使用电脑系统时经常会出现丢失找不到某些文件的情况,由于很多常用软件都是采用 Microsoft Visual Studio 编写的,所以这类软件的运行需要依赖微软Visual C运行库,比如像 QQ、迅雷、Adobe 软件等等,如果没有安装VC运行库或者安装…

2026/11/4 13:00:52

Windows系统文件dwmredir.dll丢失找不到问题解决

在使用电脑系统时经常会出现丢失找不到某些文件的情况,由于很多常用软件都是采用 Microsoft Visual Studio 编写的,所以这类软件的运行需要依赖微软Visual C运行库,比如像 QQ、迅雷、Adobe 软件等等,如果没有安装VC运行库或者安装…

2026/11/5 10:43:56

工业测温方案解析:ADS122U04与STM32F042K6的UART高精度RTD采集设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 10:43:56

STM32L031+ADS122U04:UART接口24位ADC实现PT100高精度温度采集

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 10:43:55

基于ADS122U04与MK24的HVAC高精度温度采集系统设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 10:38:55

Univer开源Web Office引擎:Canvas渲染与协同编辑实战解析

第一次看到Univer这个项目名字的时候,我下意识以为是哪个海外团队用“University”做的教育类产品。直到我翻完它的仓库和在线Demo,才发现自己差点错过一个好东西——这是一个把“在线电子表格、文档、幻灯片”全部做成开源引擎的Web Office项目&#xf…

2026/11/5 10:38:55

Foxmail数字签名与加密配置全指南:S/MIME证书实战落地

1. 邮件签名与加密不是“加个水印”或“点个锁图标”那么简单很多人第一次在Foxmail里找“签名”功能,点开设置就以为万事大吉——填上姓名、电话、公司logo,保存退出,邮件发出去带个固定落款,就觉得“搞定”。等真遇到客户问“你…

2026/11/5 10:38:55

LVS负载均衡优化:FWM标记与持久化服务实践

1. 为什么需要优化LVS调度?在企业级负载均衡场景中,Linux Virtual Server(LVS)作为四层负载均衡的经典解决方案,其性能表现直接影响着整个业务系统的稳定性。但在实际生产环境中,我们常常会遇到两个典型问题…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 0:02:07

多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中…

2026/11/5 0:02:07

大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#…

2026/11/5 0:02:07

鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑