HarmonyOS ArkTS 实战:实现一个简约倒计时器
HarmonyOS ArkTS 实战实现一个简约倒计时器项目效果本文实现的是一个基于 HarmonyOS 和 ArkTS 的简约倒计时器应用。项目中使用 ArkUI 组件完成页面布局通过State管理状态数据实现时间设置、开始/暂停/重置、倒计时结束提示、快捷时间选择和进度环显示等功能。最终运行效果如下页面主要包含以下内容顶部应用标题圆形进度环显示剩余时间大字体时间显示快捷时间选择按钮1/3/5/10/15/30分钟自定义时间设置开始/暂停/重置按钮倒计时结束状态提示页面整体采用 ArkUI 声明式布局。本文重点是演示如何在 HarmonyOS 项目中使用 ArkTS 和 ArkUI 实现一个倒计时类单页面应用。项目代码主要写在entry/src/main/ets/pages/Index.ets文件中适合作为 HarmonyOS ArkTS 入门到进阶之间的练习案例。前言倒计时器是生活中常用的工具无论是煮蛋、健身、冥想还是工作专注都需要一个简单好用的倒计时。手机自带的计时器往往功能复杂而我们需要一个界面简洁、操作方便的倒计时器。从应用开发角度来看这个项目不依赖后端接口也不需要数据库但能练习 ArkTS 中的状态管理、定时器、进度动画、按钮交互和时间计算等内容。本文基于 HarmonyOS 和 ArkTS 实现一个简约倒计时器。用户可以选择快捷时间或自定义时间开始倒计时随时暂停或重置倒计时结束时有明显的视觉提示。这个项目的核心不是简单的数字递减而是流畅的倒计时体验和直观的进度展示。每一次开始、暂停和重置本质上都是对计时器状态的管理。状态变化后页面会自动刷新这正是 ArkUI 声明式开发的基本思想。一、项目目标本次实践主要实现以下目标创建 HarmonyOS ArkTS 页面使用Entry和Component定义页面组件使用State管理页面状态使用定时器实现倒计时功能圆形进度环显示倒计时进度提供快捷时间选择按钮支持自定义分钟和秒数实现开始/暂停/重置功能倒计时结束时的状态提示时间格式化显示使用Builder封装快捷按钮和控制按钮完成一个可以运行的倒计时器页面。这个项目虽然是单页面应用但它有完整的时间设置、倒计时控制和进度显示功能比普通静态页面更适合练习 ArkTS。二、技术栈类型内容开发方向HarmonyOS 应用开发开发语言ArkTSUI 框架ArkUISDK 版本HarmonyOS API 23 及以上工程模型Stage 模型核心组件Text / Button / Column / Row / Circle / Stack / TextInput状态管理State数据处理时间计算 / 定时器 / 进度动画项目入口entry/src/main/ets/pages/Index.ets运行平台模拟器或真机本项目是 HarmonyOS 原生 ArkTS 项目。页面主体由 ArkUI 组件构建核心逻辑写在Index.ets文件中不依赖后端接口也不需要额外配置数据库。三、为什么选择倒计时器项目简约倒计时器适合作为 ArkTS 练习项目主要有以下几个原因。第一实用性强。倒计时是非常常用的功能在很多场景下都会用到。第二业务场景真实。烹饪、运动、专注、休息等场景都需要倒计时是手机必备工具之一。第三适合练习状态管理。运行状态、剩余时间、总时间、定时器ID都属于页面状态。状态变化后页面会自动刷新。第四适合练习定时器和动画。倒计时需要每秒更新进度环需要平滑动画。第五适合练习时间格式化。将秒数格式化为易读的分秒格式。第六扩展空间比较大。基础功能完成后可以继续增加多组倒计时、提示音、震动提醒、后台运行和预设模板。在本项目中剩余时间和运行状态是核心数据。页面中的时间显示和进度环都由它们计算或渲染得到。四、功能规则说明快捷时间选项1分钟、3分钟、5分钟、10分钟、15分钟、30分钟。自定义时间范围0-99分钟0-59秒。按钮状态规则当前状态主按钮副按钮初始/重置开始重置禁用运行中暂停重置暂停中继续重置倒计时结束重新开始重置时间显示格式MM:SS例如05:00表示5分钟。倒计时结束时时间显示为00:00进度环填满颜色变为绿色提示完成。五、项目结构本项目主要修改首页文件entry └── src └── main └── ets └── pages └── Index.ets其中文件作用Index.ets编写页面结构、状态数据和倒计时逻辑本文不涉及复杂路由也不需要额外创建多个页面。对于练习项目来说把主要逻辑集中在一个Index.ets文件中更方便理解。六、核心实现思路本项目的核心流程如下使用State保存总时间、剩余时间、运行状态和定时器ID用户点击快捷按钮设置时间用户也可以自定义分钟和秒数点击开始按钮启动定时器每秒减少1秒剩余时间圆形进度环显示倒计时进度点击暂停按钮停止定时器点击重置按钮回到初始状态剩余时间为0时倒计时结束格式化时间显示为分秒格式。项目中最重要的状态变量如下State isRunning: boolean false State isFinished: boolean false State totalSeconds: number 300 State remainingSeconds: number 300 State timerId: number -1 State customMinutes: string 5 State customSeconds: string 0其中状态变量作用isRunning倒计时是否运行中isFinished倒计时是否结束totalSeconds总时间秒remainingSeconds剩余时间秒timerId定时器IDcustomMinutes自定义分钟输入customSeconds自定义秒数输入remainingSeconds是本项目中最重要的数据。时间显示和进度环都依赖这个状态。七、Index.ets 完整代码打开文件entry/src/main/ets/pages/Index.ets将其中内容替换为下面代码EntryComponentstruct Index{StateisRunning:booleanfalseStateisFinished:booleanfalseStatetotalSeconds:number300StateremainingSeconds:number300StatetimerId:number-1StatecustomMinutes:string5StatecustomSeconds:string0privatequickTimes:number[][60,180,300,600,900,1800]aboutToDisappear(){this.stopTimer()}privatesetTime(seconds:number):void{if(this.isRunning)returnthis.totalSecondssecondsthis.remainingSecondssecondsthis.isFinishedfalsethis.customMinutesMath.floor(seconds/60).toString()this.customSeconds(seconds%60).toString()}privateapplyCustomTime():void{if(this.isRunning)returnletminsparseInt(this.customMinutes)||0letsecsparseInt(this.customSeconds)||0minsMath.min(Math.max(mins,0),99)secsMath.min(Math.max(secs,0),59)lettotalmins*60secsif(total0){this.setTime(total)}}privatestartTimer():void{if(this.isRunning||this.remainingSeconds0)returnthis.isRunningtruethis.isFinishedfalsethis.timerIdsetInterval((){if(this.remainingSeconds0){this.remainingSeconds--}else{this.finishTimer()}},1000)}privatepauseTimer():void{if(!this.isRunning)returnthis.isRunningfalsethis.stopTimer()}privatestopTimer():void{if(this.timerId!-1){clearInterval(this.timerId)this.timerId-1}}privateresetTimer():void{this.pauseTimer()this.remainingSecondsthis.totalSecondsthis.isFinishedfalse}privatefinishTimer():void{this.pauseTimer()this.isFinishedtruethis.remainingSeconds0}privategetProgress():number{if(this.totalSeconds0)return0return1-(this.remainingSeconds/this.totalSeconds)}privateformatTime(seconds:number):string{letminsMath.floor(seconds/60)letsecsseconds%60return${this.formatTwo(mins)}:${this.formatTwo(secs)}}privateformatTwo(value:number):string{returnvalue10?0value.toString():value.toString()}privategetRingColor():string{if(this.isFinished)return#10B981if(this.isRunning)return#0A59F7return#9CA3AF}BuilderQuickTimeButton(seconds:number){letminsMath.floor(seconds/60)Button(${mins}分钟).height(40).padding({left:16,right:16}).fontSize(14).fontColor(this.totalSecondsseconds!this.isRunning?Color.White:#4B5563).backgroundColor(this.totalSecondsseconds!this.isRunning?#0A59F7:#F3F4F6).borderRadius(20).onClick((){this.setTime(seconds)})}build(){Column(){Text(倒计时器).fontSize(28).fontWeight(FontWeight.Bold).fontColor(#182431).margin({top:22})Text(基于 HarmonyOS ArkTS 的简约计时工具).fontSize(14).fontColor(#6B7280).margin({top:8,bottom:30})Stack(){Circle().width(260).height(260).fill(#F5F7FA).stroke(#E5E7EB).strokeWidth(12)Circle().width(260).height(260).fill(Color.Transparent).stroke(this.getRingColor()).strokeWidth(12).strokeDashArray([2*Math.PI*124*this.getProgress(),2*Math.PI*124]).strokeDashOffset(2*Math.PI*124*0.25).animation({duration:1000,curve:Curve.Linear})Column(){if(this.isFinished){Text(⏰).fontSize(40).margin({bottom:8})Text(时间到).fontSize(20).fontWeight(FontWeight.Bold).fontColor(#10B981)}Text(this.formatTime(this.remainingSeconds)).fontSize(56).fontWeight(FontWeight.Bold).fontColor(this.isFinished?#10B981:#182431).fontFamily(monospace)Text(this.isRunning?倒计时中:this.isFinished?已完成:准备开始).fontSize(14).fontColor(#6B7280).margin({top:8})}}.width(280).height(280).margin({bottom:30}).justifyContent(FlexAlign.Center).alignItems(Alignment.Center)Text(快捷时间).fontSize(16).fontWeight(FontWeight.Medium).fontColor(#182431).width(100%).margin({bottom:12})Flex({wrap:FlexWrap.Wrap,justifyContent:FlexAlign.Start}){ForEach(this.quickTimes,(time:number){this.QuickTimeButton(time)},(t:number)t.toString())}.width(100%).margin({bottom:20})Text(自定义时间).fontSize(16).fontWeight(FontWeight.Medium).fontColor(#182431).width(100%).margin({bottom:12})Row(){TextInput({text:this.customMinutes,placeholder:分}).layoutWeight(1).height(48).fontSize(18).textAlign(TextAlign.Center).backgroundColor(#F5F7FA).borderRadius(12).type(InputType.Number).onChange((value:string){this.customMinutesvalue})Text(分).fontSize(16).margin({left:8,right:16})TextInput({text:this.customSeconds,placeholder:秒}).layoutWeight(1).height(48).fontSize(18).textAlign(TextAlign.Center).backgroundColor(#F5F7FA).borderRadius(12).type(InputType.Number).onChange((value:string){this.customSecondsvalue})Text(秒).fontSize(16).margin({left:8})Button(应用).height(48).margin({left:16}).padding({left:16,right:16}).fontSize(15).fontColor(Color.White).backgroundColor(#0A59F7).borderRadius(12).onClick((){this.applyCustomTime()})}.width(100%).margin({bottom:30})Row(){if(this.isRunning){Button(暂停).height(56).layoutWeight(2).fontSize(18).fontColor(Color.White).backgroundColor(#F59E0B).borderRadius(28).onClick((){this.pauseTimer()})}else{Button(this.isFinished?重新开始:开始).height(56).layoutWeight(2).fontSize(18).fontColor(Color.White).backgroundColor(#10B981).borderRadius(28).onClick((){if(this.isFinished){this.resetTimer()}this.startTimer()})}Blank().width(16)Button(重置).height(56).layoutWeight(1).fontSize(16).fontColor(this.remainingSecondsthis.totalSeconds?#EF4444:#9CA3AF).backgroundColor(this.remainingSecondsthis.totalSeconds?#FEF2F2:#F3F4F6).borderRadius(28).onClick((){this.resetTimer()})}.width(100%)}.width(100%).height(100%).padding({left:18,right:18}).backgroundColor(#F5F7FA)}}八、代码实现说明1. 倒计时核心逻辑使用setInterval每秒减少1秒剩余时间时间到0时调用finishTimerthis.timerIdsetInterval((){if(this.remainingSeconds0){this.remainingSeconds--}else{this.finishTimer()}},1000)2. 圆形进度环和番茄钟类似使用两个Circle实现进度环进度随时间增加动画平滑过渡。倒计时结束时进度环变为绿色。3. 快捷时间设置提供常用时间的快捷按钮点击即可快速设置无需手动输入。4. 自定义时间支持输入分钟和秒数点击应用设置自定义时间有范围限制防止非法值。5. 按钮状态管理根据运行状态和结束状态动态改变按钮文字和颜色运行中显示暂停按钮橙色未运行显示开始按钮绿色结束后显示重新开始重置按钮在有进度时才是红色可点击状态6. 结束状态倒计时结束时显示闹钟emoji和时间到提示进度环变绿给用户明确的反馈。九、运行项目代码编写完成后在DevEco Studio中运行项目。测试快捷时间选择、自定义时间、开始/暂停/重置功能检查倒计时是否准确进度环是否正常动画结束时是否有正确提示。十、开发中遇到的问题定时器清理页面销毁时清除定时器防止内存泄漏运行中禁止修改时间倒计时进行时不能修改时间设置自定义时间范围验证防止输入超过范围的数值结束状态处理时间到后正确显示完成状态十一、总结本文基于HarmonyOS和ArkTS实现了一个简约倒计时器。项目通过State管理计时状态使用定时器实现倒计时功能实现了快捷时间选择、自定义时间、开始/暂停/重置和进度显示等功能。这个项目展示了ArkTS中定时器使用、动画效果和状态管理的基本方法适合作为入门练习项目。