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

及时做APP开发实战(七)-专注时长实时累加实现

及时做APP开发实战(七)-专注时长实时累加实现

本文将详细介绍番茄钟专注时长的实时累加实现,让用户能够实时看到专注成果的积累。

一、问题背景

1.1 问题现象

在番茄钟应用中,用户希望实时看到专注时长的累加,而不是等到番茄钟完成才更新。原实现存在以下问题:

┌─────────────────────────────────────┐ │ 问题现象示意 │ ├─────────────────────────────────────┤ │ 专注10分钟 → 显示0分钟(未完成) │ │ 提前结束 → 专注时长丢失 │ │ 用户无法实时看到专注成果 │ └─────────────────────────────────────┘

1.2 问题分析

原代码只在番茄钟完成时一次性累加:

// 问题代码:只在完成时累加timerId=setInterval(()=>{if(this.timeLeft>0){this.timeLeft--;// 只减少剩余时间}else{this.onTimerComplete();}},1000);// 完成时一次性累加onTimerComplete(){this.totalFocusMinutes+=this.customDuration;}

问题根源

  • 专注时长totalFocusMinutes只在完成时更新
  • 无法实时反映用户的专注进度
  • 提前结束时专注时长丢失

二、解决方案

2.1 核心思路

┌─────────────────────────────────────┐ │ 解决思路 │ ├─────────────────────────────────────┤ │ 1. 新增变量记录当前番茄钟秒数进度 │ │ 2. 每秒累加,满60秒更新一次专注时长 │ │ 3. 完成时处理不足60秒的部分 │ │ 4. 区分专注时间和休息时间 │ └─────────────────────────────────────┘

2.2 变量设计

┌─────────────────────────────────────┐ │ 双变量设计 │ ├─────────────────────────────────────┤ │ totalFocusMinutes 总专注时长 │ │ (@State,用于UI显示) │ │ │ │ currentFocusSeconds 当前秒数进度 │ │ (private,用于累加计算) │ └─────────────────────────────────────┘

2.3 代码实现

@Entry@Componentstruct PomodoroTimer{@StatetotalFocusMinutes:number=0;// 总专注时长(分钟)privatecurrentFocusSeconds:number=0;// 当前番茄钟已专注秒数@StateisBreak:boolean=false;// 是否休息时间@StatetimeLeft:number=25*60;@StateisRunning:boolean=false;privatetimerId:number=-1;// 开始计时startTimer(){if(this.isRunning)return;this.isRunning=true;this.timerId=setInterval(()=>{if(this.timeLeft>0){this.timeLeft--;// 实时累加专注时长(仅在专注时间,非休息时间)if(!this.isBreak){this.currentFocusSeconds++;// 每满60秒,增加1分钟专注时长if(this.currentFocusSeconds>=60){this.totalFocusMinutes++;this.currentFocusSeconds=0;}}}else{this.onTimerComplete();}},1000);}// 计时完成onTimerComplete(){clearInterval(this.timerId);this.isRunning=false;// 处理最后不足60秒的专注时间if(this.currentFocusSeconds>0){// 四舍五入:超过30秒算1分钟if(this.currentFocusSeconds>=30){this.totalFocusMinutes++;}this.currentFocusSeconds=0;}}// 重置计时器resetTimer(){clearInterval(this.timerId);this.isRunning=false;this.currentFocusSeconds=0;// 重置专注秒数this.timeLeft=25*60;}}
  • 更改后结果图

    倒计时减少一分钟,专注计时增加一分钟

三、关键设计点

3.1 休息时间判断

if(!this.isBreak){// 仅在专注时间累加,休息时间不累加this.currentFocusSeconds++;}

这样可以确保:

  • 专注时间:累加专注时长
  • 休息时间:不累加专注时长

3.2 不足1分钟的处理

采用四舍五入策略:

┌─────────────────────────────────────┐ │ 四舍五入策略 │ ├─────────────────────────────────────┤ │ 专注45秒 → 超过30秒 → 算作1分钟 │ │ 专注20秒 → 不足30秒 → 忽略 │ └─────────────────────────────────────┘
if(this.currentFocusSeconds>=30){this.totalFocusMinutes++;}

3.3 完整UI示例

@Entry@Componentstruct FocusTimerPage{@StatetimeLeft:number=25*60;@StatetotalFocusMinutes:number=0;@StateisRunning:boolean=false;@StateisBreak:boolean=false;privatecurrentFocusSeconds:number=0;privatetimerId:number=-1;build(){Column(){// 显示总专注时长Row(){Text('今日专注').fontSize(14).fontColor('#666666')Text(`${this.totalFocusMinutes}分钟`).fontSize(24).fontWeight(FontWeight.Bold).fontColor('#FF6B6B')}.margin({bottom:20})// 进度条Progress({value:this.getProgress(),total:100,type:ProgressType.Ring}).width(200).height(200).color(this.isBreak?'#4CAF50':'#FF6B6B')// 时间显示Text(this.formatTime(this.timeLeft)).fontSize(48).fontWeight(FontWeight.Bold).margin({top:20})// 当前进度(调试用)Text(`当前进度:${this.currentFocusSeconds}`).fontSize(14).fontColor('#999999').margin({top:10})// 控制按钮Row(){Button(this.isRunning?'暂停':'开始').backgroundColor('#FF6B6B').fontColor(Color.White).onClick(()=>this.toggleTimer())Button('重置').backgroundColor('#E0E0E0').fontColor('#333333').onClick(()=>this.resetTimer()).margin({left:20})}.margin({top:30})}.width('100%').height('100%').justifyContent(FlexAlign.Center)}getProgress():number{consttotalTime=25*60;return((totalTime-this.timeLeft)/totalTime)*100;}formatTime(seconds:number):string{constmins=Math.floor(seconds/60);constsecs=seconds%60;return`${mins.toString().padStart(2,'0')}:${secs.toString().padStart(2,'0')}`;}toggleTimer(){if(this.isRunning){clearInterval(this.timerId);this.isRunning=false;}else{this.startTimer();}}startTimer(){this.isRunning=true;this.timerId=setInterval(()=>{if(this.timeLeft>0){this.timeLeft--;if(!this.isBreak){this.currentFocusSeconds++;if(this.currentFocusSeconds>=60){this.totalFocusMinutes++;this.currentFocusSeconds=0;}}}else{this.complete();}},1000);}complete(){clearInterval(this.timerId);this.isRunning=false;if(this.currentFocusSeconds>=30){this.totalFocusMinutes++;}this.currentFocusSeconds=0;}resetTimer(){clearInterval(this.timerId);this.isRunning=false;this.currentFocusSeconds=0;this.timeLeft=25*60;}}

四、效果对比

4.1 功能验证

场景修改前修改后
专注10分钟显示0分钟显示10分钟 ✅
专注25分钟完成显示25分钟显示25分钟 ✅
提前结束显示0分钟显示实际时长 ✅
休息时间也会累加不累加 ✅

4.2 数据流示意

┌─────────────────────────────────────┐ │ 实时累加流程 │ ├─────────────────────────────────────┤ │ 每秒触发 → currentFocusSeconds++ │ │ ↓ │ │ 满60秒? → totalFocusMinutes++ │ │ → currentFocusSeconds = 0 │ │ ↓ │ │ 完成/重置 → 处理剩余秒数 │ └─────────────────────────────────────┘

五、最佳实践

5.1 变量设计原则

// ✅ 正确:分离显示变量和计算变量@StatetotalFocusMinutes:number=0;// 显示用privatecurrentFocusSeconds:number=0;// 计算用// ❌ 错误:只用一个变量,无法精确控制@StatefocusSeconds:number=0;

5.2 边界条件处理

// ✅ 正确:处理不足单位时间的情况if(this.currentFocusSeconds>=30){this.totalFocusMinutes++;}// ❌ 错误:忽略剩余时间// 直接清零,丢失最后几十秒的专注成果

5.3 状态区分

// ✅ 正确:区分专注和休息if(!this.isBreak){this.currentFocusSeconds++;}// ❌ 错误:不区分状态this.currentFocusSeconds++;// 休息时间也会累加

六、总结

本文实现了专注时长的实时累加功能,核心是采用双变量设计:

  • totalFocusMinutes:用于UI显示的总时长
  • currentFocusSeconds:用于累加计算的秒数进度

同时需要注意处理边界条件(不足1分钟的部分)和区分不同状态(专注/休息),这样才能为用户提供准确的实时反馈。


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

相关文章:

  • 雷达中国官方售后服务中心|服务热线及门店官方地址权威信息公告(2026年7月更新) - 亨得利钟表维修中心
  • 2026年最新AI agent面试(01)_Agent基础与推理范式
  • 贵阳人卖金真实体验全公开:五家门店逐个跑,足金K金铂金全搞定,24小时免费上门无隐藏费用 - 小城生活闲谈
  • 带标注的蜜蜂识别数据集,识别率88.6% ,8080张图,支持yolo,coco json,voc xml,文末有模型训练代码
  • Kimi K2.6长程会话实战:13小时稳定交互架构设计
  • 小孩也能看懂的算法笔记-排序算法day1
  • ABAP 没有 @Input 注解,真正对应的是参数契约、组件映射与 RAP 输入模型
  • HarmonyOS 应用开发《掌上英语》第8篇—项目实践指南
  • 工业智能体入门指南:收藏!小白也能看懂的大模型应用
  • 【第 005 讲】Python 中的进制表示与转换:整数进制 | 前缀表示 | 进制转换算法 | 小数转换 | 进制转换工具
  • 爱回收的黄金回收靠谱吗?我做了一次完整的数据核查测评 - 资讯速览
  • 2026上海汽车贴膜店新能源专篇:特斯拉、极氪、问界车主都在找的“专车专用”贴膜店 - GrowUME
  • 知识库建设的4个万能拆解公式:从问题到可执行知识
  • 北京企业股权离婚分割律师推荐,公司股权估值增值分割万商天勤刘潞律师 - 资讯速览
  • 工厂仓库降温性价比高的工业大吊扇供应商 - GrowUME
  • GPT-Live实时语音交互:双工通信与上下文管理技术解析
  • HH-Lol-Prophet:英雄联盟对局智能分析助手,选人阶段预判队友实力
  • 欧美用户访问慢完全对策:源站、CDN、机房选址三角决策
  • KV260视觉AI开发套件入门指南与实战配置
  • OpenDDS安全实践:从零配置DDS Security实现数据加密通信
  • 多模型工作流火了,AI测试该怎么测?
  • 边缘计算 + 多模态感知:智慧电厂皮带运输 AI 识别系统是如何做到 “零误报” 的?
  • Java前端内卷到头?转行嵌入式,收藏这份高薪学习路线图!
  • K8S中Prometheus高可用集群实战:分片+Thanos+Raft告警
  • Python EXE逆向分析实战:从打包原理到源码提取与反编译
  • 北京高净值离婚律师优选,企业家大额财产分割股权保全万商天勤刘潞律师 - 资讯速览
  • EPEL仓库在RHEL/CentOS中的安装与管理指南
  • Einstein-OS Quantum:面向AI智能体的新型操作系统架构
  • 深入解析Claude的J-space与Loop机制:提升AI思考质量的关键技巧
  • 苹果Vision Pro硬件架构与供应链深度解析