发布时间:2026/7/22 23:21:07
【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/7/22 23:21:07

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

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

2026/7/22 23:21:07

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

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

2026/7/23 0:36:12

dir (obj) 与dir()

用大白话 代码例子给你讲透,先给核心结论:这两句话是在说:dir(obj) 是 Python 内置的「固定规则工具」,__dir__() 是类里「开发者自定义的钩子」,两者的返回结果永远做不到 100% 完全一样;而__dir__()返回…

2026/7/23 0:36:11

告别AI瞎写代码!18万Star开源Skills仓库,8大核心技能干货详解

文章目录一、GitHub现在有多离谱?纯文本仓库半年干到18万收藏1.1 跟普通写CLAUDE.md提示词根本不是一个东西二、30秒一键安装,小白也能直接上手2.1 必开初始化技能,一键适配你的项目三、八大王牌技能,每一个都能解决程序员痛点3.1…

2026/7/23 0:31:11

威胁狩猎实战:如何在茫茫日志中找到那只“隐蔽的熊“

"如果你等到告警才行动,你已经慢了。"——威胁狩猎的核心,不是更快地响应告警,而是在告警产生之前,就发现攻击者的踪迹。前言传统安全防御是"被动响应"的:攻击者入侵 → 触发告警 → 安全团队响应…

2026/7/22 9:29:13

Unity与Python本地通信:基于Flask的跨语言数据交换实战

1. 项目概述:为什么我们需要一个本地通信服务器?在游戏开发、数字孪生、仿真训练等众多领域,Unity作为强大的实时3D内容创作平台,其核心逻辑通常由C#驱动。然而,当我们需要进行复杂的数据分析、机器学习推理、科学计算…

2026/7/23 0:01:10

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/22 21:00:12

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…