文章目录前言效果展示实现原理代码详解状态定义主呼吸灯组件呼吸循环函数多个指示灯的错开效果控制按钮性能考量扩展玩法写在最后前言硬件设备上有个经典的视觉效果——呼吸灯。手机充电时那个慢慢亮起来又慢慢暗下去的 LED 灯Mac 睡眠时那个脉动的指示灯都给人一种设备在呼吸的生命感。在 App 界面里呼吸灯效果也很常见待机状态的提示、录音中的指示器、后台处理的标识。今天就来用 ArkUI 复刻这个效果。效果展示实现了两个呼吸灯组件一个大的主呼吸灯支持多色切换三个小的指示灯带错开的时间差实现原理呼吸灯的核心是两个属性的周期性变化属性低谷值高峰值说明| opacity | 0.3 | 1.0 | 明暗变化 || scale | 0.8 | 1.0 | 微小的缩放配合 |加上Curve.EaseInOut曲线和 1500ms 的时长就形成了慢慢亮→慢慢暗的呼吸节奏。代码详解状态定义EntryComponentstruct BreathingLightAnimation{StatebreathOpacity:number0.3StatebreathScale:number0.8StateisBreathing:booleanfalseStatecolorIndex:number0privatebreathColors:string[][#4D96FF,#FF6B6B,#6BCB77,#9B59B6,#FFD93D]build(){Column(){// ...}}}五种颜色可以循环切换给呼吸灯增加了一些可玩性。主呼吸灯组件Row(){Column().width(60).height(60).backgroundColor(this.breathColors[this.colorIndex]).borderRadius(30).opacity(this.breathOpacity).scale({x:this.breathScale,y:this.breathScale}).animation({duration:1500,curve:Curve.EaseInOut})}.width(100%).justifyContent(FlexAlign.Center).animation的duration设为 1500ms这个值很关键。太短比如 500ms就成了闪烁太长比如 3000ms用户会觉得太慢没有反应。1500ms 大约对应一次正常的呼吸周期吸气呼气所以感觉最自然。呼吸循环函数_breathCycle(){if(!this.isBreathing)return// 阶段1亮起来 放大animateTo({duration:1500,curve:Curve.EaseInOut},(){this.breathOpacity1this.breathScale1})setTimeout((){if(!this.isBreathing)return// 阶段2暗下去 缩小animateTo({duration:1500,curve:Curve.EaseInOut},(){this.breathOpacity0.3this.breathScale0.8})// 阶段2完成后开始下一轮setTimeout((){this._breathCycle()},1500)},1500)}每一轮呼吸周期是3000ms亮 1500ms 暗 1500ms。函数末尾递归调用自身形成无限循环。关键细节每个阶段开始之前都会检查this.isBreathing确保用户点击停止后动画能及时停下来。多个指示灯的错开效果底部有三个小指示灯它们共享同一个breathOpacity和breathScale但每个灯有一个微小的偏移量ForEach([0,1,2],(idx:number){Column().width(16).height(16).backgroundColor(PRESET_COLORS[idx].value).borderRadius(8).opacity(this.breathOpacityidx*0.15).scale({x:this.breathScaleidx*0.05,y:this.breathScaleidx*0.05}).animation({duration:1500,curve:Curve.EaseInOut})})通过idx * 0.15和idx * 0.05的偏移三个灯的亮度和大小有微妙的差异看起来像是有时间差的波浪式呼吸。控制按钮Row({space:8}){Button(开始呼吸).onClick((){if(this.isBreathing)returnthis.isBreathingtruethis._breathCycle()})Button(停止).onClick((){this.isBreathingfalse})Button(换颜色).onClick((){this.colorIndex(this.colorIndex1)%this.breathColors.length})}性能考量呼吸灯是持续运行的动画对性能有一定影响。几点建议控制数量同一个页面不要超过 3-5 个呼吸灯同时运行页面不可见时暂停如果呼吸灯所在的页面被切换到后台应该暂停动画使用简单的属性opacity和scale是 GPU 友好的属性不会触发重新布局扩展玩法呼吸灯效果可以有很多变体心跳模式用两段快速脉冲代替平滑过渡模拟心跳节奏渐变色彩不只改变亮度同时改变色相从蓝到紫到红循环光晕效果在主灯外面加一个更大的半透明圆圈同步做放大淡出模拟光晕声音同步配合音频振幅来调整呼吸灯的亮度写在最后呼吸灯动画的精髓在于Curve.EaseInOut 长 duration。这种曲线让动画的开头和结尾都很缓慢中间略微加速完美模拟了呼吸的自然节奏。做氛围感 UI 的时候呼吸灯是成本最低但效果最好的选择之一。