鸿蒙新特性:TimePicker 时间选择器——构建闹钟设置与时间管理
在移动应用中,精确到小时和分钟的时间选择是高频需求——设置闹钟、预约提醒、安排日程都离不开时间选择器。HarmonyOS NEXT ArkUI 提供了 TimePicker 组件,以滚轮形式直观展示时间选择交互,支持时/分/秒精度配置、12/24 小时制切换和范围限制。
本文将深入讲解 TimePicker 组件的使用方法,并构建一个完整的"闹钟设置"应用——支持时间滚轮选择、闹钟创建保存、开关切换和删除管理。
关键词:HarmonyOS、ArkUI、TimePicker、时间选择器、闹钟设置、滚轮选择
一、TimePicker 组件基础
1.1 API 概述
TimePicker 是 ArkUI 提供的时间滚轮选择组件。它以垂直滚轮的形式展示时、分(可选秒),用户上下滑动滚轮选择目标时间。
TimePicker({
selected: new Date(2026, 0, 1, 7, 0), // 预设时间:7:00
format: TimePickerFormat.HOUR_MINUTE // 显示时+分
})
.onChange((value: TimePickerResult) => {
// value.hour: 选中的小时(0-23)
// value.minute: 选中的分钟(0-59)
this.selectedHour = value.hour;
this.selectedMinute = value.minute;
})
核心属性与回调:
- selected:
TimePickerOptions中预设选中的时间,类型为Date。注意:只有hours和minutes有效,年/月/日部分被忽略。默认值为当前系统时间 - format:控制显示粒度。
TimePickerFormat.HOUR_MINUTE(时+分,默认)或TimePickerFormat.HOUR_MINUTE_SECOND(时+分+秒) - onChange(callback):用户滑动滚轮改变选中时间后触发,回调参数为
TimePickerResult对象 - useMilitaryTime:是否使用 24 小时制。
true显示 0-23,false显示 AM/PM。默认为系统设置
1.2 TimePickerResult 接口
interface TimePickerResult {
hour: number; // 选中的小时(0-23)
minute: number; // 选中的分钟(0-59)
second: number; // 选中的秒(0-59),仅 HOUR_MINUTE_SECOND 格式有效
}
hour 始终以 24 小时制返回(0-23),无论 useMilitaryTime 设置为何。如果使用 12 小时制显示(如 “7:30 PM”),hour 仍然返回 19。这个设计保证了程序逻辑的一致性——显示格式和内部值分离。
1.3 时间范围限制
通过 start 和 end 参数限制可选时间范围(API 18+):
TimePicker({
selected: new Date(),
format: TimePickerFormat.HOUR_MINUTE,
start: new Date(2026, 0, 1, 9, 0), // 最早 9:00
end: new Date(2026, 0, 1, 18, 0) // 最晚 18:00
})
超出范围的选项在滚轮上可能变灰或不可滚动。这在预约场景中非常有用——比如只允许选择工作时间的档位。
1.4 与 CalendarPicker 的配合
TimePicker 通常与 CalendarPicker 配合使用——CalendarPicker 选日期,TimePicker 选具体时间。本文 Demo 聚焦于纯时间的闹钟场景(闹钟只关心时间和重复模式,不关心具体日期),但扩展为"预约时间"时,两者组合是最常见的模式。
二、闹钟设置的整体设计
2.1 页面架构
本文 Demo 构建一个"闹钟设置"应用,模拟系统闹钟的核心体验:
AlarmPage
├── 标题栏 — "闹钟设置" + 闹钟计数
├── 组件说明卡片 — TimePicker 功能介绍
├── 消息提示区 — 操作反馈(添加/开关/删除)
├── 添加按钮 — "+ 添加闹钟"
├── TimePicker 表单(展开后)
│ ├── TimePicker — 时/分滚轮选择
│ ├── 闹钟标签 TextInput
│ ├── 取消按钮
│ └── 保存按钮
└── 闹钟列表
├── 时间 + 标签展示
├── ON/OFF 开关
└── 删除按钮
2.2 数据结构
interface AlarmItem {
id: number;
hour: number; // 0-23
minute: number; // 0-59
label: string; // 闹钟名称
enabled: boolean; // 是否开启
repeat: boolean[]; // 周几重复([一,二,三,四,五,六,日])
}
repeat 是一个 7 元素布尔数组,对应周一到周日。全部 false 表示"不重复"(单次闹钟),全部 true 表示"每天",周一到周五 true 表示"工作日"。
2.3 时间格式化
闹钟列表中的时间以 HH:MM 格式显示:
formatTime(h: number, m: number): string {
return h.toString().padStart(2, '0')
.concat(':')
.concat(m.toString().padStart(2, '0'));
}
padStart(2, '0') 确保个位数前补零——7:05 显示为 “07:05” 而非 “7:5”。数字时钟的视觉一致性要求所有时间显示的位数一致。
三、TimePicker 在闹钟设置中的应用
3.1 展开添加表单
点击"+ 添加闹钟"按钮,TimePicker 表单在按钮下方展开:
showAddAlarm(): void {
this.pickHour = 7;
this.pickMinute = 0;
this.pickLabel = '';
this.showPicker = true;
this.message = '';
}
默认时间设为早上 7:00——这是一个用户体验决策:大多数用户的第一个闹钟设置在早上 7 点左右,默认靠近这个时间可以减少滚轮滑动次数。
3.2 TimePicker 配置
TimePicker({
selected: new Date(2026, 0, 1, this.pickHour, this.pickMinute),
format: TimePickerFormat.HOUR_MINUTE
})
.onChange((value: TimePickerResult) => {
this.onTimeChange(value);
})
format 使用 HOUR_MINUTE——闹钟场景不需要秒级精度。selected 中的年/月/日(2026, 0, 1)仅作为占位符,实际有效的只有 hour 和 minute。
3.3 保存闹钟
saveAlarm(): void {
let newAlarm: AlarmItem = {
id: this.nextId,
hour: this.pickHour,
minute: this.pickMinute,
label: this.pickLabel.trim().length > 0 ? this.pickLabel.trim() : '闹钟',
enabled: true,
repeat: [false, false, false, false, false, false, false]
};
this.nextId++;
this.alarms = [newAlarm].concat(this.alarms.slice());
this.showPicker = false;
}
新闹钟默认开启(enabled: true),默认不重复(repeat 全 false)。[newAlarm].concat(this.alarms.slice()) 将新闹钟插入列表头部(最新的在上面)。
标签如果为空则默认显示"闹钟"——这是一个友好的兜底策略,避免空白标签。
四、闹钟管理功能
4.1 开关切换
每个闹钟卡片有一个 ON/OFF 开关按钮:
toggleAlarm(id: number): void {
let idx = -1;
for (let i = 0; i < this.alarms.length; i++) {
if (this.alarms[i].id === id) { idx = i; break; }
}
if (idx < 0) return;
let updated = this.alarms.slice();
updated[idx] = {
id: updated[idx].id,
hour: updated[idx].hour,
minute: updated[idx].minute,
label: updated[idx].label,
enabled: !updated[idx].enabled, // 翻转开关状态
repeat: updated[idx].repeat
};
this.alarms = updated;
}
ArkTS 的 @State 要求数组元素修改也必须创建新对象。所以不能直接 this.alarms[idx].enabled = ...,需要完整地展开并替换整个元素。这是 ArkUI 响应式系统最需要适应的"额外步骤"——但换来的好处是 UI 状态的可预测性强,不会有"改了一部分 UI 没更新"的 bug。
4.2 删除闹钟
deleteAlarm(id: number): void {
this.alarms = this.alarms.slice()
.filter((a: AlarmItem) => a.id !== id);
}
标准的 slice + filter 模式。删除后的消息反馈"闹钟已删除"通过 showMessage 显示在顶部的临时消息区域。
4.3 消息反馈
操作完成后,顶部消息栏短暂显示反馈:
showMessage('闹钟已添加 — 07:30')
showMessage('已开启 — 08:00')
showMessage('闹钟已删除')
消息是瞬时的——下次操作会覆盖上一条消息。在实际应用中,消息栏可能会增加一个自动消失的定时器(2-3 秒后自动清空),避免长时间占用屏幕空间。
五、重复模式
5.1 智能识别
getRepeatText 方法将 boolean[] 数组转换为人类可读的重复描述:
getRepeatText(r: boolean[]): string {
if (r.every(v => !v)) return '不重复'; // 全 false
if (r.every(v => v)) return '每天'; // 全 true
// 工作日:周一到周五 true,周六日 false
if (r.slice(0,5).every(v => v) && !r[5] && !r[6]) return '工作日';
// 周末:周六日 true,周一到周五 false
if (!r[0] && !r[1] && !r[2] && !r[3] && !r[4] && r[5] && r[6]) return '周末';
// 自定义:列出每个选中的星期
return ['一','二','三','四','五','六','日']
.filter((_, i) => r[i]).join('、');
}
这个函数展示了"模式匹配"的逻辑分层:
- 先匹配最简单的全否/全是
- 再匹配常见的预设组合(工作日、周末)
- 最后回退到逐项列举
匹配顺序很重要——"工作日"也是"周一、周二、周三、周四、周五"的子集,但应该优先匹配为预设名称而非逐项列举。
六、视觉设计
6.1 闹钟卡片的状态表达
闹钟卡片根据 enabled 状态改变视觉效果:
- 开启:时间文字黑色(
#1a1a2e),标签灰色(#9999AA),开关按钮蓝色 - 关闭:所有文字变灰(
#CCCCDD),开关按钮灰色
这种"整体灰化"的设计比仅改变开关按钮颜色更直观——用户扫一眼列表就能看到哪些闹钟是开启的,不需要逐个检查开关状态。
6.2 空状态
当没有任何闹钟时,显示空状态引导:
⏰
暂无闹钟
点击上方按钮添加第一个闹钟
空状态不是简单的"无数据"——它包含图标(建立隐喻)、状态说明(告知当前情况)和行动指引(明确下一步操作)。
七、交互流程演示
7.1 添加第一个闹钟
进入页面,列表为空,显示空状态。点击"+ 添加闹钟",TimePicker 表单展开,默认显示 07:00。滑动滚轮调整到 08:30,输入标签"上班闹钟",点击"保存闹钟"。表单关闭,列表中出现第一条闹钟(开启状态,蓝色开关)。
7.2 添加更多闹钟
再次点击"+ 添加闹钟",设置 12:00,标签"午餐",保存。再添加 18:00,标签"健身",保存。列表已有 3 条闹钟。
7.3 关闭闹钟
点击"午餐"闹钟的 ON 按钮,开关变为灰色 OFF,整个卡片文字变灰。
7.4 删除闹钟
点击"健身"闹钟的"删除"按钮,该闹钟从列表中消失,提示"闹钟已删除"。列表中剩余 2 条闹钟。
八、总结
本文通过"闹钟设置"这个实战案例,全面讲解了 ArkUI TimePicker 组件的使用方法。核心知识点包括:
- TimePicker API:selected、format(HOUR_MINUTE/HOUR_MINUTE_SECOND)、onChange
- TimePickerResult:hour(0-23)、minute(0-59)字段
- 闹钟管理:添加(concat 头部插入)、删除(filter)、开关切换(slice + 新对象替换)
- @State 响应式规则:数组元素修改必须创建完整新对象
- UI 状态表达:enabled 控制卡片整体灰化 + 开关颜色
- 重复模式智能识别:全否→不重复、全是→每天、工作日→周末→逐项列举
TimePicker 组件将"时间选择"这个复杂的滚轮交互封装为简洁的 API——开发者不需要处理滚轮惯性的物理计算,不需要处理时间上下溢(如分钟从 59 滚到 0),不需要处理 12/24 小时制的格式转换。组件的内部机制保证了时间始终处于有效范围,开发者只需在 onChange 回调中捕获 hour 和 minute 并更新业务状态。
更多推荐



所有评论(0)