鸿蒙新特性:TimePicker 时间选择器详解——打造一个完整的闹钟模拟器
时间选择是移动应用中继日期选择之后的第二高频时间交互。HarmonyOS NEXT ArkUI 提供了 TimePicker 组件,以经典的两列滚轮(时/分)交互模式让用户快速选定时间。与 DatePicker 的年月日三级滚轮不同,TimePicker 专注于时和分的选择,交互更加简洁直接。
本文将深入讲解 TimePicker 的 API 设计和使用方法,并通过一个完整的"闹钟模拟器"实战案例,展示 12/24 小时制切换、剩余时间倒计时、标签命名和快捷时间预设等功能。
关键词:HarmonyOS、ArkUI、TimePicker、时间选择、闹钟、倒计时
一、TimePicker 组件概览
TimePicker 采用两列滚轮式交互——左列是小时(0-23),右列是分钟(0-59)。与 DatePicker 相比,TimePicker 少了"天"的维度,使用户能更快速地选择精确到分钟的时间点。
它的典型应用场景包括:
- 闹钟设置(选择提醒时间)
- 预约时段(选择开始时间)
- 提醒设定(选择通知触发时间)
- 倒计时起始时间选择
结合 DatePicker 和 TextClock,这三个组件构成了 ArkUI 时间相关组件体系的完整拼图。
二、TimePicker 核心 API
2.1 构造函数
TimePicker({
selected: Date // 初始选中的时间
})
TimePicker 的构造函数只有一个参数 selected,接受一个 JavaScript Date 对象。组件会自动从 Date 对象中提取时和分,忽略年、月、日部分。
// 默认选中早上 7:00
TimePicker({
selected: new Date(2026, 0, 1, 7, 0)
})
2.2 onChange 回调与 TimePickerResult
当用户滑动滚轮改变选中时间时,onChange 被触发,返回 TimePickerResult 对象:
interface TimePickerResult {
hour: number; // 0-23(始终为 24 小时制)
minute: number; // 0-59
}
值得注意的重要设计:hour 始终是 24 小时制(0-23),无论页面上是否启用了 12 小时制显示。这意味着 TimePicker 的内部数据模型是纯粹的 24 小时制,12 小时制的 AM/PM 显示完全由应用层负责转换。这种设计让数据与显示分离,避免了"上午 7 点"和"下午 7 点"(19 点)在数据层上的歧义。
TimePicker({ selected: new Date(2026, 0, 1, 7, 0) })
.onChange((value: TimePickerResult) => {
this.alarmHour = value.hour!; // 7(24h 制)
this.alarmMinute = value.minute!;
})
2.3 关键属性
| 属性 | 类型 | 说明 |
|---|---|---|
.useMilitaryTime() |
- | 强制 24 小时制显示 |
.loop() |
boolean |
是否循环滚动 |
.disappearTextStyle() |
PickerTextStyle |
非选中项文字样式 |
.selectedTextStyle() |
PickerTextStyle |
选中项文字样式 |
| ! |

三、12/24 小时制转换
TimePicker 内部使用 24 小时制存储小时值,但很多场景需要展示 12 小时制(带 AM/PM)。我们需要在应用层实现转换逻辑:
// 24h → 12h 数字
fmt12h(h: number): string {
const h12 = h % 12;
if (h12 === 0) return '12'; // 0点→12点, 12点→12点
return h12.toString();
}
// 判断上午/下午
ampm(h: number): string {
return h < 12 ? '上午' : '下午';
}
// 格式化完整时间字符串
fmtTimeString(): string {
if (this.use24h) {
return this.alarmHour.toString().padStart(2, '0')
.concat(':', this.alarmMinute.toString().padStart(2, '0'));
}
return this.ampm(this.alarmHour).concat(' ',
this.fmt12h(this.alarmHour), ':',
this.alarmMinute.toString().padStart(2, '0'));
}
三个关键转换规则:
0 点在 12 小时制中显示为12:00(午夜)12 点在 12 小时制中显示为12:00(正午)13-23 点对 12 取模得到 1-11,且标注为"下午"
四、实战:闹钟模拟器
我们实现一个完整的闹钟模拟器,核心功能包括:
- TimePicker 时间选择:两列滚轮选择时和分
- 12/24 时制切换:Toggle 开关控制显示格式
- 闹钟标签命名:TextInput 自定义闹钟名称
- 剩余时间倒计时:设定后实时显示距闹钟响铃还有多久
- 快捷时间预设:8 个常用时间一键设定
4.1 核心状态
@State alarmHour: number = 7; // 0-23
@State alarmMinute: number = 0;
@State use24h: boolean = true; // 时制开关
@State alarmLabel: string = '起床闹钟';
@State alarmActive: boolean = false; // 闹钟是否已设定
@State remainText: string = ''; // 剩余时间文字
4.2 剩余时间计算
设定闹钟后,需要计算当前时间与闹钟时间的差值。核心逻辑是:如果闹钟时间已过,则自动推到明天同一时间。
updateRemain(): void {
if (!this.alarmActive) {
this.remainText = '未设置';
return;
}
const now = new Date();
let alarm = new Date(
now.getFullYear(), now.getMonth(), now.getDate(),
this.alarmHour, this.alarmMinute, 0
);
// 如果闹钟时间已过,推到明天
if (alarm.getTime() <= now.getTime()) {
alarm = new Date(alarm.getTime() + 24 * 60 * 60 * 1000);
}
// 计算小时和分钟差
const diff = alarm.getTime() - now.getTime();
const h = Math.floor(diff / (1000 * 60 * 60));
const m = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
this.remainText = '还有 '.concat(h.toString(), ' 小时 ', m.toString(), ' 分钟');
}
为了保持剩余时间更新,设定闹钟后开启一个定时器每分钟刷新:
setAlarm(): void {
this.alarmActive = true;
this.updateRemain();
if (this.intervalId !== -1) {
clearInterval(this.intervalId);
}
// 每 30 秒刷新剩余时间
this.intervalId = setInterval(() => { this.updateRemain(); }, 30000);
}
页面销毁时记得清理定时器:
aboutToDisappear(): void {
if (this.intervalId !== -1) {
clearInterval(this.intervalId);
}
}
4.3 快捷时间预设
提供 8 个常用闹钟时间的快捷按钮,覆盖从早到晚的典型场景:
Row() {
this.QuickBtn('06:30', 6, 30)
this.QuickBtn('07:00', 7, 0)
this.QuickBtn('07:30', 7, 30)
this.QuickBtn('08:00', 8, 0)
}
Row() {
this.QuickBtn('12:00', 12, 0)
this.QuickBtn('14:00', 14, 0)
this.QuickBtn('18:30', 18, 30)
this.QuickBtn('22:00', 22, 0)
}
QuickBtn 使用 @Builder 提取为独立方法:
@Builder
QuickBtn(label: string, h: number, m: number) {
Text(label)
.fontSize(13).fontColor('#1677FF').fontWeight(FontWeight.Medium)
.padding({ top: 8, bottom: 8, left: 14, right: 14 })
.borderRadius(10).backgroundColor('#EEF3FF').margin({ right: 8 })
.onClick(() => {
this.alarmHour = h;
this.alarmMinute = m;
if (this.alarmActive) { this.updateRemain(); }
})
}
4.4 时间显示区域
一个醒目的时间展示卡片,使用大号等宽字体显示当前设定的闹钟时间:
Row() {
Text('⏰').fontSize(36).margin({ right: 14 })
Column() {
Text(this.fmtTimeString())
.fontSize(40).fontColor('#1a1a2e').fontWeight(FontWeight.Bold)
.fontFamily('monospace').margin({ bottom: 6 })
Text(this.alarmActive ? '闹钟已开启' : '闹钟未开启')
.fontSize(12)
.fontColor(this.alarmActive ? '#52C41A' : '#9999AA')
}
}
如果闹钟已设定,额外显示一个橙色的剩余时间标签,让用户一目了然地知道距离闹钟触发还有多久。
4.5 设定/取消按钮
按钮在不同状态下有完全不同的外观和行为:
- 未设定状态:蓝色按钮,文字"设定闹钟"
- 已设定状态:红色按钮,文字"取消闹钟"
if (!this.alarmActive) {
Button('设定闹钟')
.fontSize(16).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
.width('100%').height(48).borderRadius(24)
.backgroundColor('#1677FF')
.onClick(() => { this.setAlarm(); })
} else {
Button('取消闹钟')
.fontSize(16).fontColor('#FFFFFF').fontWeight(FontWeight.Bold)
.width('100%').height(48).borderRadius(24)
.backgroundColor('#FF4D4F')
.onClick(() => { this.cancelAlarm(); })
}
五、与其他时间组件的配合
TimePicker 很少单独使用,它通常与 DatePicker、TextClock、TextTimer 配合构成完整的时间交互方案:
| 组合 | 场景 | 说明 |
|---|---|---|
| DatePicker + TimePicker | 预约/日程 | 先选日期再选时间 |
| TimePicker + TextClock | 闹钟 | 设置时间 + 显示当前时间 |
| TimePicker + TextTimer | 倒计时 | 选定截止时间 + 倒计时显示 |
例如,一个完整的"预约提醒"功能可能需要:DatePicker 选日期 → TimePicker 选时间 → TextTimer 显示剩余时间。这三个组件的组合能覆盖绝大部分时间相关的交互需求。
六、完整交互流程
- 初始状态:TimePicker 显示 07:00,时间卡片显示"07:00",闹钟未设定
- 选择时间:滑动时和分滚轮,时间卡片实时同步更新显示的时间
- 切换时制:关闭"24 小时制"开关,显示变为"上午 7:00"
- 命名标签:在输入框中输入"晨会提醒"
- 快捷设定:点击"08:00"快捷按钮,时间跳转到 8:00
- 设定闹钟:点击蓝色"设定闹钟"按钮,剩余时间开始计算并显示
- 取消闹钟:点击红色"取消闹钟"按钮,回到未设定状态
七、总结
TimePicker 是 ArkUI 时间组件家族中"小而精"的一员。它的 API 极简——只有一个 selected 参数和一个 onChange 回调——但配合应用层的 12/24 时制转换和时间计算逻辑,可以构建出功能完备的闹钟应用。
本文通过"闹钟模拟器"这个实战案例,覆盖了:
- TimePicker 的基本用法和 TimePickerResult 接口
- 12/24 小时制的应用层转换逻辑(三个关键规则)
- 剩余时间的跨天计算(已过时间自动推到明天)
- 快捷时间预设的 @Builder 复用
- 定时器的生命周期管理(aboutToDisappear 清理)
TimePicker 配合 DatePicker 和 TextTimer,三者共同构成了鸿蒙应用中时间选择与管理的完整能力矩阵。掌握了 TimePicker,你就补全了时间交互的最后一块拼图。
更多推荐



所有评论(0)