AtomGit Flutter 鸿蒙客户端:倒计时与触觉反馈

📅 2026/7/9 18:12:07
AtomGit Flutter 鸿蒙客户端:倒计时与触觉反馈
倒计时不只是数字递减——配合触觉反馈可以为放松体验增加一层物理感让用户即使闭着眼睛也能感知时间的流动。一、设计理念让用户不必看屏幕白噪音模块的核心使用场景是用户闭上眼睛沉浸在放松状态中。在这种场景下屏幕上的视觉信息对用户是不可见的。传统的解决方式是音频提示叮的一声但 E-Brufen 当前没有音频播放能力。于是我们转向了触觉通道视觉通道眼睛闭着 ↓ 不可用 听觉通道无音频播放 ↓ 不可用 触觉通道 ← E-Brufen 的主反馈通道 ↓ 用户感知到震动 → 知道时间在流逝 → 保持放松状态二、定时器选项设计2.1 预设时长finalListint_durations[15,30,60,90];Wrap(spacing:8,children:[..._durations.map((d)ChoiceChip(label:Text($d分),selected:_remainingSec0_remainingSec~/60d,onSelected:(_)setState((){_remainingSecd*60;widget.settings.timerDurationd;// 持久化偏好}),)),ChoiceChip(label:constText(不限),selected:_remainingSec0,onSelected:(_)setState(()_remainingSec0),),])设计考量时长适用场景触觉反馈次数15 分钟快速放松、课间休息14 次轻触 1 次重触30 分钟午休小憩29 次轻触 1 次重触60 分钟深度放松59 次轻触 1 次重触90 分钟完整睡眠周期89 次轻触 1 次重触不限背景白噪音办公等无不启动 Timer⚠️ 不限选项不启动 Timer_remainingSec 0作为特殊标记。此时_startCountdown()直接 return不会消耗系统资源。三、Timer.periodic 倒计时实现3.1 核心代码void_startCountdown(){_countdown?.cancel();// 取消旧的 Timer防重复if(_remainingSec0)return;// 不限模式直接返回_countdownTimer.periodic(constDuration(seconds:1),(timer){if(!_isPlaying){// 手动停止 → 取消计时timer.cancel();return;}setState((){_remainingSec--;if(_remainingSec0){// 时间到_onTimerDone();timer.cancel();return;}// ⏰ 每分钟一次轻触觉——无声的报时if(_remainingSec%600){HapticFeedback.lightImpact();}});});}3.2 状态流程图用户点击播放 ↓ _startCountdown() → Timer.periodic(每秒) ↓ 每秒回调 ├─ !_isPlaying? → timer.cancel() (用户手动停止) ├─ _remainingSec 0? → _onTimerDone() (自然结束) ├─ _remainingSec % 60 0? → lightImpact() (分钟标记) └─ _remainingSec-- (继续倒计时)★ Insight ─────────────────────────────────────_remainingSec % 60 0是无声提醒的核心。用户闭眼放松时每分钟一次轻触觉让他知道又过了一分钟而不需要睁眼看屏幕。这是 E-Brufen 最精妙的设计细节之一——它把必须看变成了可以感受。─────────────────────────────────────────────────四、完成时的双重反馈void_onTimerDone(){setState((){_isPlayingfalse;});_pulse.stop();_pulse.reset();HapticFeedback.heavyImpact();// 强烈的唤醒震动if(mounted){ScaffoldMessenger.of(context).showSnackBar(constSnackBar(content:Text(时间到放松结束 ),duration:Duration(seconds:2),),);}}双重信号确保用户一定感知到结束heavyImpact()— 强烈的触觉即使在口袋中也能感知SnackBar— 视觉确认如果屏幕可见⚠️if (mounted)检查是必须的——Timer 回调可能在 Widget 已销毁后触发如用户快速返回首页不检查会导致setState() called after dispose()崩溃。五、HapticFeedback 类型详解Flutter 提供四种触觉反馈强度类型强度持续时间E-Brufen 中的使用lightImpact()轻~10ms✅ 每分钟标记mediumImpact()中~15ms可用于场景切换确认heavyImpact()重~20ms✅ 定时结束唤醒selectionClick()极轻~5ms可用于 emoji 选择反馈选择lightImpact而非selectionClick的原因selectionClick太轻在口袋或桌面上可能感知不到。lightImpact提供了足够的感知强度而不至于惊醒放松中的用户。六、播放/停止的对称控制void_togglePlay(){setState((){_isPlaying!_isPlaying;if(_isPlaying){_pulse.repeat(reverse:true);// 启动脉冲动画_startCountdown();// 启动倒计时}else{_pulse.stop();// 停止动画_pulse.reset();_countdown?.cancel();// 取消倒计时}});}一对对称操作播放时同时启动动画和 Timer停止时同时取消两者。这确保了动画和计时永远同步。七、资源释放overridevoiddispose(){_pulse.dispose();// 释放 AnimationController_countdown?.cancel();// 取消 Timer防止内存泄漏super.dispose();}释放顺序先dispose动画可能有回调引用 Timer再cancelTimer。两个异步资源都要清理——漏掉任何一个都会导致内存泄漏。八、时间格式化String_formatTime(int s){finalms~/60;finalsecs%60;return${m.toString().padLeft(2, 0)}:${sec.toString().padLeft(2, 0)};}// 03:45, 00:30, 01:00上一篇白噪音场景的视觉设计下一篇ChangeNotifier 模式轻量级状态管理作者简介E-Brufen DevFlutter 鸿蒙开发者。触觉反馈设计基于 HapticFeedback API 在鸿蒙 6.0 真机上的实测体验,项目地址AtomGit - E-Brufen。