如何实现类似TrueCaller的Flutter流畅波纹动画效果?
实现类似TrueCaller的流畅波纹动画
要实现TrueCaller那种连续向外扩散、逐渐淡出的波纹效果,你当前的方案存在几个问题:每个波纹独立控制动画导致同步性差,来回缩放的逻辑不符合扩散式波纹的需求,且没有处理透明度的渐变。下面是更贴合需求的实现思路和代码:
核心实现思路
- 用单个AnimationController控制所有波纹的动画进度,避免多控制器的同步问题
- 每个波纹通过
Interval设置不同的动画时间区间,实现依次扩散的效果 - 波纹动画同时包含尺寸放大和透明度降低两个维度,模拟自然扩散消失的过程
- 循环播放动画,保持波纹的连续性
优化后的代码实现
class WaveRippleWidget extends StatefulWidget { final double maxRadius; // 波纹最大扩散半径 final Color rippleColor; // 波纹颜色 final int rippleCount; // 波纹数量 final int animationDuration; // 单条波纹完成一次动画的时长(毫秒) const WaveRippleWidget({ super.key, required this.maxRadius, this.rippleColor = Colors.green, this.rippleCount = 3, this.animationDuration = 2000, }); @override State<WaveRippleWidget> createState() => _WaveRippleWidgetState(); } class _WaveRippleWidgetState extends State<WaveRippleWidget> with TickerProviderStateMixin { late AnimationController _animationController; @override void initState() { super.initState(); _animationController = AnimationController( vsync: this, duration: Duration(milliseconds: widget.animationDuration), )..repeat(); // 循环播放动画 } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Center( child: SizedBox( width: widget.maxRadius * 2, height: widget.maxRadius * 2, child: Stack( alignment: Alignment.center, children: List.generate(widget.rippleCount, (index) { // 为每个波纹设置时间区间,错开动画起始时间 final animation = Tween<double>(begin: 0, end: 1).animate( CurvedAnimation( parent: _animationController, curve: Interval( index / widget.rippleCount, 1.0, curve: Curves.easeOut, ), ), ); return AnimatedBuilder( animation: animation, builder: (context, child) { final progress = animation.value; return Container( width: progress * widget.maxRadius * 2, height: progress * widget.maxRadius * 2, decoration: BoxDecoration( shape: BoxShape.circle, color: widget.rippleColor.withOpacity(1 - progress), ), ); }, ); }), ), ), ); } }
使用示例
在需要的地方直接调用这个Widget即可:
WaveRippleWidget( maxRadius: 100, // 根据需求调整最大半径 rippleColor: Colors.green.withOpacity(0.4), rippleCount: 3, animationDuration: 2000, )
关键细节说明
- 同步控制:单个AnimationController循环播放,所有波纹基于它的进度计算自己的动画状态,完美保证同步性
- 时间错开:通过
Interval(index / rippleCount, 1.0)让每个波纹依次启动,形成连续扩散的视觉效果 - 双维度动画:尺寸从0放大到最大半径,透明度从1降到0,符合真实波纹的扩散消失逻辑
- 性能优化:用AnimatedBuilder结合Container实现,比多个独立StatefulWidget更高效
内容的提问来源于stack exchange,提问作者Sinh Phan
相关产品推荐
相关产品推荐

