鸿蒙新特性——TextTimer 计时器组件详解

📅 2026/6/28 6:10:44
鸿蒙新特性——TextTimer 计时器组件详解
一、引言倒计时是移动端应用中最常见的功能之一。电商 App 的秒杀倒计时、外卖 App 的配送倒计时、验证码页面的 60 秒重发倒计时、番茄钟的 25 分钟专注倒计时、运动 App 的跑步计时——这些场景都有一个共同的核心需求一个可控的、格式化显示的、精确到秒的计时器。传统实现计时器需要组合setInterval 格式化函数 自动刷新 UI 开始/暂停/重置状态管理。代码量不小而且有几个容易出错的点定时器的清除时机防止内存泄漏、计时精度setInterval 的累积偏差、跨页面的时间同步切到后台再回来时间不准。如果还要支持正计时和倒计时两种模式的切换状态管理和控制逻辑会更加复杂。HarmonyOS 提供了TextTimer组件——一个将计时逻辑和文本显示合二为一的组件。它内置了精确的计时引擎不受 setInterval 累积偏差影响自动处理时间格式化mm:ss或HH:mm:ss通过TextTimerController提供标准的开始/暂停/重置控制接口。开发者不需要管理定时器生命周期不需要编写格式化函数——只需配置参数和绑定控制器。本文通过一个倒计时器Demo 深入讲解 TextTimer 组件的核心用法如何设置倒计时和正计时如何使用 TextTimerController 控制计时如何通过 format 定制时间显示格式如何构建预设时长选择器阅读完本文你将能够使用TextTimer组件实现倒计时和正计时两种模式使用TextTimerController的start()/pause()/reset()方法控制计时流程使用format()方法定制时间显示格式结合onTimer回调实现进度条、颜色变化等联动效果构建预设时长选择和自定义计时持续时间的交互二、TextTimer 组件 API 总览2.1 构造函数TextTimer(options?:TextTimerOptions)TextTimer 的构造函数接收一个可选配置对象定义计时模式、时长和控制器interfaceTextTimerOptions{isCountDown?:boolean;// 是否倒计时模式默认 false正计时count?:number;// 计时范围单位毫秒最大 8640000024小时默认 60000controller?:TextTimerController;// 控制器用于开始/暂停/重置}最简用法——默认 60 秒倒计时TextTimer({isCountDown:true,count:60000})2.2 TextTimerController —— 计时控制器TextTimerController是控制 TextTimer 行为的核心接口提供三个方法方法用途说明start()开始/继续计时首次调用开始计时暂停后调用继续计时pause()暂停计时保持当前时间再次 start() 后继续reset()重置计时回到初始状态倒计时回到 count 值正计时回到 0使用模式privatetimerController:TextTimerControllernewTextTimerController();TextTimer({isCountDown:true,count:300000,controller:this.timerController})// 控制按钮Button(开始).onClick((){this.timerController.start();})Button(暂停).onClick((){this.timerController.pause();})Button(重置).onClick((){this.timerController.reset();})注意reset()后需要重新调用start()才开始计时。pause()后调用start()会从暂停位置继续不会从初始值重新开始。2.3 format —— 时间显示格式format()方法控制时间的显示格式TextTimer({isCountDown:true,count:3600000}).format(HH:mm:ss)// 显示为 01:00:00格式字符串显示示例适用场景mm:ss05:30短时间1h如验证码、番茄钟HH:mm:ss01:05:30长时间1h如赛事计时、配送计时mm:ss.SS05:30.50需要毫秒精度如运动计时HH:mm:ss.SS01:05:30.50完整格式默认格式为mm:ss。2.4 核心样式方法方法用途示例fontSize(value)字体大小.fontSize(64)fontColor(value)字体颜色.fontColor(#1a1a2e)fontWeight(value)字体粗细.fontWeight(FontWeight.Bold)fontFamily(value)字体族等宽字体推荐.fontFamily(monospace)使用monospace等宽字体可以避免数字变化时文字左右跳动——每个数字字符在等宽字体中占据相同宽度。2.5 onTimer —— 计时回调onTimer在每次计时更新时触发每秒一次提供两个参数TextTimer({isCountDown:true,count:300000,controller:this.timerController}).onTimer((utc:number,elapsedTime:number){// utc: 当前显示的绝对时间戳较少使用// elapsedTime: 已经过的时间单位毫秒this.progressMath.round((elapsedTime/this.totalTime)*100);})elapsedTime是计时器开始后累计的时间倒计时模式从 0 递增到 count计时结束正计时模式从 0 开始持续递增利用elapsedTime可以计算进度百分比驱动进度条、颜色变化、振动提醒等联动效果。2.6 倒计时 vs 正计时TextTimer 通过isCountDown参数切换两种模式模式isCountDowncount 含义显示内容倒计时true倒计时的初始时长ms从 count 递减到 0正计时false无效正计时没有上限从 0 开始递增倒计时模式下count必须在 0 ~ 8640000024 小时之间。超出范围的值会被替换为默认值 600001 分钟。正计时模式下count参数无效——计时器从 0 开始持续增加没有上限。三、Demo 设计倒计时器3.1 功能概述Demo 是一个倒计时器页面支持倒计时和正计时两种模式大号时间显示64sp 的等宽字体醒目展示剩余/已过时间6 种预设时长1 分钟、3 分钟、5 分钟、10 分钟、25 分钟番茄钟、60 分钟开始/暂停/继续/重置控制三种状态未开始、运行中、已暂停对应不同的按钮组合倒计时/正计时模式切换分段按钮切换两种模式显示格式切换Toggle 控制是否显示小时位mm:ss ↔ HH:mm:ss进度可视化倒计时模式下彩色进度条实时反映剩余时间比例蓝→橙→红三级变色3.2 状态管理StateisCountDown:booleantrue;// 倒计时/正计时StatetimerCount:number300000;// 当前时长msStateisRunning:booleanfalse;// 是否运行中StateisPaused:booleanfalse;// 是否已暂停StateshowHours:booleanfalse;// 是否显示小时StateelapsedPercent:number0;// 已过时间百分比privatetimerController:TextTimerControllernewTextTimerController();三个布尔状态isRunning、isPaused组合出三种 UI 状态!isRunning !isPaused未开始 —— 显示开始按钮isRunning运行中 —— 显示暂停和重置按钮!isRunning isPaused已暂停 —— 显示继续和重置按钮3.3 TextTimer 核心配置TextTimer({isCountDown:this.isCountDown,count:this.timerCount,controller:this.timerController}).format(this.showHours?HH:mm:ss:mm:ss).fontSize(64).fontColor(#1a1a2e).fontWeight(FontWeight.Bold).fontFamily(monospace).onTimer((utc:number,elapsedTime:number){if(this.isCountDownthis.timerCount0){this.elapsedPercentMath.min(100,Math.round((elapsedTime/this.timerCount)*100));}})关键细节format()通过showHours布尔值动态切换——不重新创建组件只改变显示格式fontFamily(monospace)确保数字不跳动——这在计时器中是重要的 UI 细节onTimer中计算elapsedPercent用于驱动进度条注意使用Math.min(100, ...)防止超过 100%3.4 控制器操作startTimer(){if(this.isPaused){this.timerController.start();// 从暂停位置继续}else{this.timerController.reset();// 首次开始前先重置this.timerController.start();}this.isRunningtrue;this.isPausedfalse;}pauseTimer(){this.timerController.pause();this.isRunningfalse;this.isPausedtrue;}resetTimer(){this.timerController.reset();this.isRunningfalse;this.isPausedfalse;this.elapsedPercent0;}startTimer()中的逻辑值得注意如果之前已暂停直接start()继续如果是从头开始更改了时长或切换了模式先reset()再start()。TextTimerController 本身不跟踪状态——状态管理完全由开发者的 State 变量负责。3.5 进度条联动进度条是倒计时体验的重要组成部分直观展示剩余时间Row(){Row().width(${this.elapsedPercent}%).height(4).borderRadius(2).backgroundColor(this.elapsedPercent80?#FF4D4F:// 80% → 红色紧急this.elapsedPercent50?#FF9800:// 50% → 橙色注意#1677FF// 50% → 蓝色正常).animation({duration:500,curve:Curve.Linear})}.width(80%).height(4).borderRadius(2).backgroundColor(#F2F3F5)进度条长度表示已过时间的百分比颜色从蓝到橙到红渐变——接近截止时间时自动变红提醒用户时间紧迫。3.6 页面结构┌──────────────────────────────────────────┐ │ ⏱️ 倒计时器深色标题栏 │ ├──────────────────────────────────────────┤ │ TextTimer 组件说明卡片 │ ├──────────────────────────────────────────┤ │ ┌ 倒计时 ──────────────────────────┐ │ │ │ │ │ │ │ 05:00 │ │ │ │ ████████░░░░░░░░ 50% │ │ │ │ │ │ │ └───────────────────────────────────┘ │ ├──────────────────────────────────────────┤ │ ┌ 控制按钮 ────────────────────────┐ │ │ │ [ ▶ 开始 ] │ │ │ │ 或 [ ⏸ 暂停 ] [ ↺ 重置 ] │ │ │ │ 或 [ ▶ 继续 ] [ ↺ 重置 ] │ │ │ └───────────────────────────────────┘ │ ├──────────────────────────────────────────┤ │ ┌ 计时模式 ────────────────────────┐ │ │ │ [ 倒计时 ] [ 正计时 ] │ │ │ └───────────────────────────────────┘ │ ├──────────────────────────────────────────┤ │ ┌ 预设时长 ────────────────────────┐ │ │ │ [1分钟] [3分钟] [5分钟] │ │ │ │ [10分钟] [25分钟] [60分钟] │ │ │ └───────────────────────────────────┘ │ ├──────────────────────────────────────────┤ │ ┌ 显示格式 ────────────────────────┐ │ │ │ 显示时 [Toggle] │ │ │ └───────────────────────────────────┘ │ └──────────────────────────────────────────┘四、TextTimer 组件的最佳实践4.1 控制器与 UI 状态分离TextTimerController 只负责计时器的底层控制start/pause/reset不跟踪是否在运行等 UI 状态。这意味着你需要用 State 变量管理 UI 状态并在控制器操作中同步更新// 好的做法控制器操作 State 同步this.timerController.pause();this.isRunningfalse;this.isPausedtrue;// 不好的做法只操作控制器State 不同步// 结果UI 不更新按钮显示错误this.timerController.pause();三个 UI 状态未开始/运行中/已暂停通过isRunning和isPaused的布尔组合表达在 build() 中用条件渲染来显示不同的按钮。4.2 预设时长的选择对于倒计时功能预设时长选择可以提升用户体验——用户不需要手动输入时间一键点击即可privatepresets:PresetItem[][{label:1 分钟,ms:60000},{label:3 分钟,ms:180000},{label:5 分钟,ms:300000},{label:10 分钟,ms:600000},{label:25 分钟,ms:1500000},// 番茄钟标准时长{label:60 分钟,ms:3600000}];预设的选择原则覆盖常用场景1/3/5 分钟用于短操作25 分钟用于专注60 分钟用于长时间有清晰的标签“分钟而非min”——面向中文用户切换预设时自动重置计时器——防止用户困惑旧计时还在跑新时长已设置4.3 format 的动态切换format()在计时过程中可以动态切换——TextTimer 会自动调整显示格式不影响计时的内部状态。这意味着倒计时跑到一半时切换mm:ss↔HH:mm:ss计时不会中断当时长 1 小时时HH:mm:ss会显示为00:mm:ss——这是预期行为而非 bug建议根据时长自动选择格式——时长 1 小时默认用HH:mm:ss 1 小时默认用mm:ss。Demo 中将选择权交给用户通过 Toggle 切换但也可以自动化。4.4 等宽字体的重要性计时器的数字每秒变化一次。如果使用比例字体如默认的系统字体数字 “1” 和 “5” 的宽度不同导致数字变化时整个文本左右微微跳动。这个跳动在 64sp 大字体下尤为明显。解决方式设置fontFamily(monospace)。等宽字体中每个字符宽度相同数字变化不会产生布局抖动。4.5 count 参数的限制倒计时模式下的count参数有硬限制范围0 ~ 8640000024 小时超出范围的值会被替换为 600001 分钟这意味着 TextTimer 不适合超过 24 小时的计时场景如距离生日还有 X 天对于超过 24 小时的倒计时如活动倒计时需要结合 Date 计算 自定义文本显示或使用多个 TextTimer 分别显示天/时/分/秒。4.6 页面生命周期与计时器TextTimer 在页面不可见时如切换到其他 Tab 或应用退到后台继续计时——其内部使用系统时间差来保证精度而非依赖 setInterval 的累加。这意味着用户切到后台几分钟再回来计时器显示的时间是正确的基于实际时间差而非前台运行时间不需要额外处理onPageShow/onPageHide生命周期不需要手动暂停/恢复——TextTimer 内部自行处理但注意如果倒计时在后台走到了 0回到前台时onTimer不会收到到期的回调。如果需要计时结束的精确触发如播放音效、弹出通知应该在onTimer中检查elapsedTime count而非依赖恰好触发一次。五、完整代码结构TextTimerPage (~295 行) ├── 接口 │ └── PresetItem — 预设时长数据接口 ├── 状态变量 │ ├── State isCountDown — 倒计时/正计时 │ ├── State timerCount — 当前时长ms │ ├── State isRunning / isPaused — 控制器状态 │ ├── State showHours — 格式切换 │ ├── State elapsedPercent — 进度百分比 │ └── State selectedPreset — 当前选中的预设 ├── 实例 │ ├── timerController: TextTimerController │ └── presets: PresetItem[] — 6 种预设时长 ├── 方法 │ ├── startTimer() / pauseTimer() / resetTimer() │ └── selectPreset() / formatString() ├── 视图 │ ├── 标题栏 — ⏱️ 倒计时器 │ ├── 说明卡片 — TextTimer 组件介绍 │ ├── 计时显示区TextTimer 进度条 │ ├── 控制按钮开始/暂停/继续/重置 │ ├── 模式切换倒计时/正计时 │ ├── 预设时长选择 │ └── 格式切换 Toggle └── 无 Builder——所有布局内联六、总结本文通过一个倒计时器Demo 深入讲解了 HarmonyOS 中的TextTimer 计时器组件。TextTimer 将精确计时、时间格式化和文本渲染整合为一个声明式组件通过TextTimerController提供标准化的控制接口通过format()灵活配置显示格式通过onTimer回调实现进度联动。核心要点回顾TextTimer 是计时引擎 显示器的二合一组件内部使用系统时间差保证精度不受 setInterval 偏差影响外部通过声明式参数控制行为和样式。开发者不需要管理定时器生命周期。TextTimerController 提供三个标准操作start()开始/继续pause()暂停reset()回到初始值。控制器不追踪 UI 状态——状态管理由开发者用 State 变量负责。isCountDown 切换两种计时模式倒计时从count递减到 0适合秒杀、验证码、番茄钟正计时从 0 开始递增适合运动计时、工作计时。format() 自定义显示格式mm:ss适合短时间HH:mm:ss适合长时间。格式可在计时过程中动态切换不影响计时内部状态。等宽字体是计时器的 UI 细节fontFamily(monospace)避免数字变化时的布局抖动——这个细节在 64sp 大字体下尤为明显。onTimer 实现进度联动通过elapsedTime参数计算进度百分比驱动进度条、颜色变化、振动等联动效果——构建丰富的计时体验。TextTimer 是 ArkUI 中时间推移的可视化组件——它不只是一个显示数字的 Text而是一个集成了计时逻辑和显示控制的完整组件。正是这种逻辑 显示的一体化设计使得在 HarmonyOS 中实现一个倒计时器只需几行代码而不是几十行 setInterval format 的手动组合。七、扩展思考TextTimer 覆盖了基础的计时需求但在实际项目中计时功能有更多变化验证码倒计时这是 TextTimer 最常见的实战场景。在发送验证码按钮旁边显示60s 后重发倒计时结束后按钮恢复可点击。实现时需要注意倒计时值60 秒和按钮禁用状态需要同步——onTimer 中检查 elapsedTime count 时恢复按钮。全屏番茄钟TextTimer 可以结合背景色变化、音效、振动等构建完整的番茄工作法体验。倒计时到 0 时触发全屏提示——这个到 0的判断在 onTimer 中进行。多段计时器某些场景需要多个计时阶段——如高强度间歇训练HIIT在运动 30s → 休息 10s之间循环。这需要在 onTimer 中检测当前阶段是否结束自动切换到下一个阶段并重置控制器。TextTimer 与 TextClock 的区别TextClock 显示的是系统当前时间如15:30:00TextTimer 显示的是计时时间如05:00。TextClock 持续更新但不可控制TextTimer 需要控制器操作但显示的是相对时间。两者在功能上互补——如闹钟页面可以同时用 TextClock 显示当前时间和 TextTimer 显示倒计时。与后端的时间同步对于需要精确到秒的活动倒计时如秒杀、拍卖前端的 TextTimer 应以后端返回的活动结束时间为准。在创建 TextTimer 前先计算后端结束时间 - 当前服务器时间 剩余毫秒数将此差值作为count参数。理解 TextTimer 的定位——可控的、格式化的时间流逝显示组件——是正确使用它的关键。它不是时钟那是 TextClock 的职责不是日期选择器那是 DatePicker/TimePicker 的职责而正是这种让我告诉你还剩多少时间的单一职责使得 TextTimer 成为了秒杀、验证码、番茄钟等所有需要可视化时间线场景的最佳选择。通过本文的 Demo——倒计时器页面你将 TextTimer 组件与控制器、预设选择和进度条组合在一起构建了一个完整的计时工具。这个页面展示了 TextTimer 作为计时引擎 显示器的核心价值——用最简洁的 API 完成最高频的需求。