计时器是移动应用中最基础也最常用的功能之一。从番茄钟到倒计时提醒,从运动计时到烹饪定时,计时器无处不在。HarmonyOS NEXT ArkUI 提供了 TextTimer 组件——一个以数字文本形式自动显示计时的专用组件,无需手动刷新 UI,组件内部自动驱动时间变化。

本文将深入讲解 TextTimer 组件的使用方法,并构建一个完整的"专注计时器"应用——支持预设时长选择、倒计时控制、暂停恢复、完成追踪和进度可视化。

关键词:HarmonyOS、ArkUI、TextTimer、计时器、番茄钟、倒计时、专注训练

一、TextTimer 组件基础

1.1 API 概述

TextTimer 是 ArkUI 提供的文本计时器组件,以 HH:mm:ss.SS 格式自动显示时间。它不同于普通的 Text 组件——TextTimer 内部维护一个计时引擎,随时间自动更新显示内容,无需开发者编写定时器逻辑。

TextTimer({
  isCountDown: true,              // 倒计时模式
  count: 25 * 60 * 1000,          // 25分钟(毫秒)
  controller: this.controller     // TextTimerController 实例
})
  .format('mm:ss')                // 显示格式
  .fontSize(64)                   // 字号
  .fontColor('#1a1a2e')           // 颜色
  .onTimer((utc: number, elapsedTime: number) => {
    // utc: 当前时间戳(毫秒)
    // elapsedTime: 已用时间(毫秒)
  })

核心参数说明:

  • isCountDowntrue 为倒计时(从 count 倒数到 0),false 为正计时(从 0 开始递增)。默认为 false
  • count:倒计时模式下的初始时长,单位为毫秒。最大值 86400000(24 小时),默认 60000(1 分钟)。正计时模式下此参数无效
  • controller:TextTimerController 实例,提供 start()pause()reset() 三个控制方法
  • format:时间显示格式字符串,支持 HH(时)、mm(分)、ss(秒)、SS(毫秒)。默认 'HH:mm:ss.SS'
  • onTimer:时间变化回调,两个参数——utc 为当前时间戳,elapsedTime 为从启动开始已过去的毫秒数

1.2 TextTimerController

TextTimerController 是控制计时器行为的关键对象:

private controller: TextTimerController = new TextTimerController();

// 三个核心方法:
this.controller.start();   // 开始计时
this.controller.pause();   // 暂停计时
this.controller.reset();   // 重置计时

三个方法的行为说明:

  • start():启动计时器。如果当前是暂停状态,则从暂停位置继续;如果已重置,则从初始值开始。重复调用不会产生副作用(不会加速计时)
  • pause():暂停计时器。计时器保持在当前值,再次 start() 时从该位置继续。如果计时器未启动,调用无效
  • reset():重置计时器到初始值。倒计时模式回到 count 值,正计时模式回到 0。重置后计时器停止

1.3 与 TextClock 的区别

很多开发者会混淆 TextTimer 和 TextClock:

特性 TextTimer TextClock
显示内容 计时数值(MM:SS) 当前系统时间
时间来源 内部计时引擎 系统时钟
可控性 可开始/暂停/重置 不可控(自动跟随系统时间)
典型场景 番茄钟、倒计时、运动计时 时钟展示、世界时间
格式 format() 自定义 系统区域设置
回调 onTimer(每次变化触发) 无回调

简言之,TextTimer 是"计时工具",TextClock 是"时钟显示"。

二、专注计时器的整体设计

2.1 页面架构

本文 Demo 构建一个"专注计时器"应用,模拟番茄钟工作法的核心体验:

FocusTimerPage
├── 标题栏 — "专注计时器" + 状态标签(就绪/计时中/已暂停)
├── 组件说明卡片 — TextTimer 功能介绍
├── 计时器显示区 — TextTimer 组件 + 进度条
├── 控制按钮 — 开始/暂停 + 重置
├── 统计面板 — 完成次数 + 当前时长
└── 时长预设列表 — 6 个预设选项

2.2 状态管理

页面维护以下核心状态:

@State duration: number = 25 * 60 * 1000;  // 当前时长(毫秒)
@State isRunning: boolean = false;          // 是否运行中
@State isPaused: boolean = false;           // 是否已暂停
@State sessionCount: number = 0;            // 完成次数
@State elapsedTime: number = 0;             // 已用时间(毫秒)
@State selectedPreset: number = 25;         // 当前选中预设(分钟)
private completedFlag: boolean = false;     // 防止重复计数
private controller: TextTimerController = new TextTimerController();

计时器有三种状态:

  1. 就绪(idle):isRunning=false, isPaused=false —— 初始状态或重置后
  2. 计时中(running):isRunning=true, isPaused=false —— 倒计时进行中
  3. 已暂停(paused):isRunning=true, isPaused=true —— 计时被暂停

这三种状态通过标题栏的状态标签可视化——分别显示灰色"就绪"、绿色"计时中"、橙色"已暂停"。

2.3 六种预设时长

getPresets(): TimerPreset[] {
  return [
    { label: '5分钟', minutes: 5, ms: 5 * 60 * 1000 },
    { label: '15分钟', minutes: 15, ms: 15 * 60 * 1000 },
    { label: '25分钟', minutes: 25, ms: 25 * 60 * 1000 },
    { label: '30分钟', minutes: 30, ms: 30 * 60 * 1000 },
    { label: '45分钟', minutes: 45, ms: 45 * 60 * 1000 },
    { label: '60分钟', minutes: 60, ms: 60 * 60 * 1000 }
  ];
}

25 分钟是番茄钟工作法的标准时长——由 Francesco Cirillo 在 1980 年代提出,基于"人的注意力集中周期约为 25 分钟"的研究。5 分钟和 15 分钟适合短任务或休息,45 分钟和 60 分钟适合深度工作。

预设列表使用单选模式——选中项高亮为蓝色背景白色文字,未选中项保持白色背景。点击预设时如果计时器正在运行,先重置再切换时长。
在这里插入图片描述

三、计时器控制

3.1 选择预设时长

selectPreset(ms: number, minutes: number): void {
  if (this.isRunning || this.isPaused) {
    this.controller.reset();
  }
  this.duration = ms;
  this.selectedPreset = minutes;
  this.isRunning = false;
  this.isPaused = false;
  this.elapsedTime = 0;
  this.completedFlag = false;
  this.timerKey++;  // 强制刷新组件
}

切换预设时确保:

  1. 如果计时器正在运行或暂停,先调用 controller.reset() 重置
  2. 更新所有状态变量回到初始状态
  3. timerKey++ 强制 ArkUI 重建 TextTimer 组件(因为 count 是构造函数参数,仅改变 @State duration 可能不触发组件重建)

3.2 开始与暂停

startTimer(): void {
  if (this.isRunning) return;
  if (this.isPaused) {
    this.isPaused = false;
  }
  this.controller.start();
  this.isRunning = true;
  this.completedFlag = false;
}

pauseTimer(): void {
  if (!this.isRunning || this.isPaused) return;
  this.controller.pause();
  this.isPaused = true;
}

注意 startTimer 中处理了"从暂停恢复"的情况:如果当前已暂停(isPaused=true),先清除暂停标记再启动,保证 isRunningisPaused 状态的正确转换。

暂停状态下再次点击"开始"相当于"继续"——从暂停位置恢复倒计时。这与点击"重置"后再"开始"不同——重置会回到初始时长。

3.3 重置

resetTimer(): void {
  this.controller.reset();
  this.isRunning = false;
  this.isPaused = false;
  this.elapsedTime = 0;
  this.completedFlag = false;
}

重置将所有状态恢复到初始值,但保留 duration(当前选择的时长)不变。

3.4 按钮状态联动

控制按钮根据计时器状态动态切换:

// 中间按钮:运行中显示"暂停",否则显示"开始"
if (this.isRunning && !this.isPaused) {
  Text('暂停')     // 橙色背景
    .onClick(() => { this.pauseTimer(); })
} else {
  Text('开始')     // 蓝色背景
    .onClick(() => { this.startTimer(); })
}

这是一个常见的 UI 模式——"开始"和"暂停"共用同一个按钮位置,根据状态切换文字、颜色和行为,减少按钮数量同时保持操作清晰。
在这里插入图片描述

四、完成追踪与进度可视化

4.1 检测完成

onTimer 回调在计时器每次变化时触发,我们用它检测倒计时是否归零:

onTimerTick(utc: number, elapsedTime: number): void {
  this.elapsedTime = elapsedTime;
  if (elapsedTime >= this.duration && !this.completedFlag && this.isRunning) {
    this.completedFlag = true;
    this.sessionCount++;
    this.isRunning = false;
  }
}

关键设计:completedFlag 防止重复计数。onTimer 可能在 elapsedTime >= duration 后继续触发多次(如高精度格式 SS 导致的额外回调),completedFlag 确保一次倒计时只计一次完成。

isRunning 在完成时自动设为 false——计时器虽然内部停止显示为 00:00,但我们仍需要更新 UI 状态来反映"已完成"。

4.2 进度条

在计时器下方有一个进度条,实时反映倒计时进度:

Row()
  .height(4)
  .width(this.duration > 0 ?
    ((this.duration - Math.max(0, this.duration - this.elapsedTime)) / this.duration * 100)
      .toString().concat('%') : '0%')
  .borderRadius(2)
  .backgroundColor('#1677FF')
  .animation({ duration: 500, curve: Curve.Linear })

进度条计算逻辑:

  1. this.duration - this.elapsedTime = 剩余时间
  2. Math.max(0, ...) = 防止负数(倒计时归零后)
  3. this.duration - remaining = 已用时间
  4. / this.duration * 100 = 百分比

.animation() 让进度条宽度变化平滑过渡(500ms linear),而不是每次跳变。

4.3 完成次数统计

统计面板展示两个关键指标:

  • 完成次数:通过 sessionCount 追踪,每个完整倒计时周期结束后 +1
  • 当前时长:显示当前选择的预设时长(如"25分钟")

完成次数是累积的——在同一页面内多次完成计时器会持续累加。页面关闭后数据丢失(@State 存储在内存中)。持久化可以使用 PersistentStorage 保存到本地。

五、TextTimer 的高级用法

5.1 时间格式自定义

format() 方法支持四种时间单位:

.format('mm:ss')       // 分:秒(05:23)
.format('HH:mm:ss')    // 时:分:秒(01:05:23)
.format('ss')          // 仅秒(323)
.format('mm:ss.SS')    // 分:秒.百分秒(05:23.45)

注意:format 字符串区分大小写——HHhh 都表示小时,但 mmMM 不同(MM 是月份,会被替换为默认值)。正确的格式是 HHmmssSS

对于倒计时场景,最常用的是 'mm:ss'(分钟级别精度),对于秒杀倒计时,可能需要 'HH:mm:ss' 甚至 'mm:ss.SS'(亚秒级精度)。

5.2 正计时模式

isCountDown: false(默认值)时,TextTimer 进入正计时模式——从 00:00 开始递增:

TextTimer({ isCountDown: false, controller: this.controller })
  .format('mm:ss')

正计时的 count 参数无效(或不填)。计时器会一直递增,直到调用 pause()reset()。适用于运动计时、工作记录等场景。

5.3 字体样式

TextTimer 作为文本组件,支持丰富的字体样式:

TextTimer(...)
  .fontSize(64)                 // 字号
  .fontColor('#1a1a2e')        // 颜色
  .fontWeight(FontWeight.Bold) // 粗细
  .fontStyle(FontStyle.Normal) // 斜体/正常
  .fontFamily('HarmonyOS Sans') // 字体
  .textShadow({                 // API 12+ 文字阴影
    radius: 4,
    color: '#00000020',
    offsetX: 2,
    offsetY: 2
  })

这些属性与普通 Text 组件的对应属性行为一致。

5.4 内容修改器(API 12+)

contentModifier() 允许更高级的内容定制:

TextTimer(...)
  .contentModifier(myContentModifier)

通过 ContentModifier<TextTimerConfiguration> 可以在计时器文本上叠加图标、背景或额外的文本装饰。这是比简单字体样式更灵活的自定义方式。

六、交互流程演示

6.1 启动默认计时

进入页面,默认选中"25 分钟"。状态标签显示灰色"就绪"。点击蓝色"开始"按钮,TextTimer 从 25:00 开始倒数,状态标签变为绿色"计时中",进度条开始从左向右延伸。

6.2 暂停与继续

计时器运行到 18:43 时,点击橙色"暂停"按钮。计时器停在 18:43,状态标签变为橙色"已暂停"。再次点击"开始",计时器从 18:43 继续倒数。

6.3 切换预设

计时器运行中,点击"45 分钟"预设。计时器自动重置,切换到 45 分钟,等待用户点击"开始"。

6.4 完成一次计时

倒计时归零(00:00),“完成次数"从 0 变为 1。状态回到"就绪”。

6.5 连续专注

继续点击"开始",完成第二次 25 分钟倒计时。"完成次数"变为 2。通过累积计数追踪当天的专注时长——2 次 × 25 分钟 = 50 分钟。

七、实际应用中的扩展

7.1 番茄钟完整工作流

本文 Demo 实现了番茄钟的核心计时功能。完整的番茄钟工作法还包括:

  • 短休息(5 分钟):每完成一个番茄钟后自动进入休息
  • 长休息(15-30 分钟):每完成 4 个番茄钟后进入长休息
  • 任务列表:关联每个番茄钟与具体任务
  • 统计图表:日/周/月的番茄钟数量统计

这些可以在当前 Demo 基础上扩展——通过添加"休息模式"状态和自动切换逻辑实现。

7.2 后台计时

TextTimer 在应用进入后台或锁屏时不会继续触发 onTimer 回调(组件不可见)。对于需要后台计时的场景(如烘焙定时),需要结合后台任务管理 API 或使用系统通知在倒计时结束时提醒用户。

7.3 多计时器并行

一个页面可以放置多个 TextTimer 实例,每个有独立的 controller。例如运动训练应用可能同时追踪"本轮用时"和"总用时"两个计时器。

八、总结

本文通过"专注计时器"这个实战案例,全面讲解了 ArkUI TextTimer 组件的使用方法。核心知识点包括:

  1. TextTimer API:isCountDown、count、controller、format、onTimer
  2. TextTimerController:start()、pause()、reset() 三个控制方法
  3. 计时器状态机:就绪 → 计时中 → 已暂停 → 就绪(重置后)
  4. 完成检测:onTimer 回调 + completedFlag 防重复计数
  5. 进度条可视化:elapsedTime / duration 实时百分比 + animation 平滑过渡
  6. 预设时长选择:单选列表 + 运行时安全切换

TextTimer 组件将"计时"这个看似简单的需求做了深度封装——开发者不需要手动管理 setInterval/clearInterval,不需要处理时间格式化,不需要担心前后台切换的状态一致性问题。组件内部维护的计时引擎保证显示精度和性能,开发者只需关注业务逻辑——选什么时长、何时开始、完成后做什么。


Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐