当前位置: 首页 > news >正文

鸿蒙实战:运动健康类应用核心组件——倒计时组件设计与实现

完整源码:SportTrackDemo-CountdownOverlay.ets

上一篇文章我们完成了运动健康类控制交互按钮组件,本篇内容接上一篇点击「开始」按钮后页面呈现倒计时组件,并且增加了视觉感。

在运动健康类应用中,倒计时是用户点击「开始运动」后的第一个交互。3、2、1、开始,这短短几秒的动画既给用户准备时间,也营造仪式感。本文将从设计思路出发,分享一套流畅的倒计时数字动画组件,并支持数字变化回调,方便配合语音播报等拓展功能。关于语音播报,下一篇文章详细讲解设计思路以及功能封装。

一、设计思路

1.1 为什么需要倒计时?

倒计时的核心作用是给用户准备时间。用户点击「开始运动」后,不会立即开始记录,而是有3秒时间收起手机、调整姿势。同时,倒计时动画也营造了仪式感,让开始运动更有“出发”的感觉。

1.2 动画设计原则

原则说明实现方式
醒目数字要足够大,吸引注意力字体大小 120,绿色#4CAF50
节奏感每个数字停留时间一致每个数字约1秒
衔接感倒计时结束与运动开始无缝衔接「开始」飞入底部按钮位置
不遮挡倒计时浮在地图上方,背景透明背景色透明,只显示数字
可扩展支持回调通知父组件当前数字提供onNumberChange回调

1.3 动画时序设计

数字3: [放大300ms] → [停留400ms] → [淡出300ms] 总计1000ms 数字2: [放大300ms] → [停留400ms] → [淡出300ms] 总计1000ms 数字1: [放大300ms] → [停留400ms] → [淡出300ms] 总计1000ms 开始: [放大300ms] → [停留400ms] → [飞入300ms] 总计1000ms ──────────────────────────────────────────────── 总时长: 约 4 秒

1.4 为什么最后加个「开始」?

一开始我也只想做 3、2、1,但总感觉缺点什么,就像人说话卡壳了说了一半。虽然只是显示文字,但如果加入语音播报呢?把运动看成一场正式的比赛,裁判员那句「开始」才是真正的命令。3、2、1 只是准备,「开始」才是出发的信号。

1.5 动画曲线选择

动画阶段使用曲线原因
数字放大Curve.FastOutSlowIn先快后慢,有弹性感,数字弹出有力
数字淡出Curve.EaseOut缓慢消失,自然过渡
飞入Curve.EaseIn先慢后快,模拟被吸入的效果

二、效果预览

三、核心代码实现

3.1 组件属性定义

@Componentexportstruct CountdownOverlay{// 是否激活倒计时(由父组件控制显示/隐藏)@PropisActive:boolean=false;// 背景颜色,默认透明,不遮挡下层内容@PropbgColor:ResourceStr='rgba(0, 0, 0, 0)';// 倒计时结束回调(动画全部执行完毕后触发)onFinish?:()=>void;// 数字/文字变化回调(每个数字/文字显示时触发)onNumberChange?:(text:string)=>void;// 当前显示的倒计时文字(3、2、1、开始)@StateprivatecountdownText:string='';// 文字缩放比例(用于放大/缩小动画)@StateprivatecountdownScale:number=1.0;// 文字透明度(用于淡入/淡出动画)@StateprivatecountdownOpacity:number=1.0;// 文字垂直偏移量(用于开始飞入动画)@StateprivatecountdownOffsetY:number=0;// 动画是否正在执行(防止重复触发)@StateprivateisAnimating:boolean=false;// 倒计时步骤数组privatereadonlysteps:string[]=['3','2','1','开始'];// 当前执行到第几步privatecurrentStepIndex:number=0;// 存储所有定时器ID,用于组件销毁时清理privatetimeouts:number[]=[];}

3.2 构建方法

build(){if(this.isActive){Stack(){Column().width('100%').height('100%').backgroundColor(this.bgColor)Text(this.countdownText).fontSize(this.countdownText==='开始'?90:120).fontWeight(FontWeight.Bold).fontColor('#4CAF50').scale({x:this.countdownScale,y:this.countdownScale}).opacity(this.countdownOpacity).offset({y:this.countdownOffsetY})}.width('100%').height('100%').onAppear(()=>{this.resetToDefault();this.startCountdown();}).onDisAppear(()=>{this.clearAllTimeouts();this.resetToDefault();}).hitTestBehavior(HitTestMode.Block)}}

3.3 核心动画逻辑

privateresetToDefault():void{this.countdownText='';this.countdownScale=1.0;this.countdownOpacity=1.0;this.countdownOffsetY=0;this.isAnimating=false;this.currentStepIndex=0;}privatestartCountdown():void{if(this.isAnimating)return;this.isAnimating=true;this.playStepAnimation();}privateplayStepAnimation():void{if(this.currentStepIndex>=this.steps.length){this.isAnimating=false;this.onFinish?.();return;}consttext=this.steps[this.currentStepIndex];constisLastStep=(text==='开始');// 更新显示文字this.countdownText=text;// 回调出去,播放语音this.onNumberChange?.(text);this.countdownScale=0.3;this.countdownOpacity=1;this.countdownOffsetY=0;this.getUIContext().animateTo({duration:300,curve:Curve.FastOutSlowIn,onFinish:()=>{consttimeoutId=setTimeout(()=>{if(isLastStep){this.getUIContext().animateTo({duration:300,curve:Curve.EaseIn,onFinish:()=>{this.currentStepIndex++;this.playStepAnimation();}},()=>{this.countdownScale=0.1;this.countdownOffsetY=200;this.countdownOpacity=0;});}else{this.getUIContext().animateTo({duration:300,curve:Curve.EaseOut,onFinish:()=>{this.currentStepIndex++;this.playStepAnimation();}},()=>{this.countdownScale=0.5;this.countdownOpacity=0;});}},400);this.timeouts.push(timeoutId);}},()=>{this.countdownScale=1.2;});}privateclearAllTimeouts():void{for(constidofthis.timeouts){clearTimeout(id);}this.timeouts=[];}

设计说明

  • countdownText初始为空,动画从 3 开始自然执行,无需特殊处理索引
  • 使用animateTo实现动画,onFinish回调串联步骤
  • setTimeout控制停留时间,让用户看清每个数字
  • onNumberChange回调:每个数字/文字显示时立即通知父组件,方便同步语音播报
  • onDisAppear清理所有定时器并重置状态,避免内存泄漏

四、父组件使用示例

@StateisCountdownActive:boolean=false;privatespeechManager:SpeechManager=SpeechManager.getInstance();privatestartCountdown():void{this.isCountdownActive=true;}// 在 build 中CountdownOverlay({isActive:this.isCountdownActive,onNumberChange:(text:string)=>{// 动画显示什么数字/文字,就播报什么this.speechManager.speakCountdownText(text);},onFinish:()=>{this.isCountdownActive=false;this.startTracking();}})

五、踩坑经验

问题原因解决方案
背景不透明遮挡地图背景色设置了不透明使用rgba(0,0,0,0)透明背景
点击穿透到下层按钮倒计时层未阻止触摸添加.hitTestBehavior(HitTestMode.Block)
「开始」字体太大与数字使用相同字号条件判断设置不同字号(开始90,数字120)
动画与组件销毁冲突组件销毁时动画仍在执行onDisAppear中清理定时器并重置状态
数字重复出现初始值与动画第一帧重复countdownText初始设为空字符串

七、总结

该组件可直接集成到跑步、骑行、步行等运动场景中使用,也适用于任何需要倒计时功能的应用。通过onNumberChange回调,父组件可以实时感知倒计时的每一个数字/文字,轻松扩展语音播报、日志记录等功能。

本文通过完整的代码示例,演示了如何设计一个流畅的倒计时组件,我分享的不仅仅是如何实现这个动画,而是动画的本质,是在特定的时间做什么样的“事情”通过一连串的时间-动作完成一套动画。动画也分很多种类而这个动画很简单,还有很多复杂的动画通过一系列计算完成某一个动作。

如果觉得本文对你有帮助,请点赞、收藏、转发,谢谢!

http://www.jsqmd.com/news/672003/

相关文章:

  • 别再只会用BUFGMUX了!深入对比BUFGMUX、BUFGMUX_CTRL与BUFGCTRL,搞懂Xilinx时钟网络选择
  • Qwen-Image-Edit镜像免配置:内置CUDA 12.1+cuDNN 8.9+PyTorch 2.3全栈环境
  • 用Python给基金/股票做个体检:5行代码计算你的持仓年化收益、波动和夏普比率
  • 口碑好的行政诉讼律师探讨,哪家律所的服务更专业 - 工业设备
  • 2026年英国陶瓷展 The Advanced Ceramics Show - 中国组团单位- 新天国际会展 - 新天国际会展
  • WorkshopDL终极指南:免费解锁Steam创意工坊模组,跨平台游戏玩家的完美解决方案
  • 告别开机黑屏闪烁!荔枝派Lichee Zero上实现丝滑启动Logo的保姆级教程
  • 7步掌握Ryujinx:终极Nintendo Switch模拟器配置实战指南
  • 录播姬BililiveRecorder:专业直播录制与修复完整指南
  • 3分钟搞定:Axure RP中文语言包让你的原型设计效率翻倍
  • EasyClaw 是什么?一篇讲清它能做什么、适合谁、怎么开始用 - PC修复电脑医生
  • 3步搞定系统优化:Win11Debloat极简指南
  • 手把手用GD32F307C-EVAL板调试Timer0互补PWM(含死区与刹车功能)
  • Java的java.lang.StackWalker调用栈截取与异常链在错误报告中的增强
  • K210+ESP8266图传太慢?手把手教你优化图像压缩与TCP传输,让帧率翻倍
  • 车载场景问答准确率从63%跃升至91.7%:Dify动态上下文管理与多模态指令微调实战手记(含CAN总线语义注入代码)
  • ESP-IDF的Python依赖管理,远不止一个requirements.txt:深入聊聊虚拟环境与工具链的耦合
  • pkNX宝可梦编辑器:Switch世代游戏修改的终极指南
  • 嘉善老房翻新咨询哪家
  • 商城网站建设哪家便宜?电商初创公司省钱建站实战攻略 - FaiscoJeff
  • 探讨有实力的别墅电梯推荐制造商,哪家口碑和价格更优 - 工业推荐榜
  • # 023、AutoSAR AP核心:自适应应用(AA)与执行管理(EM)
  • 用OpenCV和Python搞定红绿灯识别:从视频处理到轮廓检测的完整实战
  • 在美国怎么看中国电视 - 博客万
  • 从一次USB设备通信失败说起:深入调试CRC-5校验错误的全过程
  • Windows 10终极清理指南:用Windows10Debloater一键删除预装软件和系统垃圾
  • 【通信】基于卡尔曼的混合预编码技术用于多用户毫米波大规模MIMO系统研究附Matlab代码
  • STM32G474硬件IIC+DMA驱动OLED避坑指南:从软件IIC迁移到DMA的完整流程
  • 2026年阳澄湖大闸蟹公司最新TOP实力排行/白玉大闸蟹,清水大闸蟹,阳澄湖白玉蟹,阳澄湖白玉大闸蟹,正宗阳澄湖白玉蟹 - 品牌策略师
  • 黑苹果终极实战指南:OpenCore长期维护机型EFI深度解密