如何在Flutter中实现类似ChatGPT应用的语音气泡动画
在Flutter中实现类似ChatGPT语音对话的流畅动画
这类动画核心是模拟语音波动的动态波形效果,通过控制一组矩形条的高度、透明度变化,配合循环动画驱动来实现流畅的视觉表现。以下是具体实现方案:
1. 基础波形动画实现
先创建一个可复用的波形动画组件,通过AnimationController循环驱动,随机更新波形条高度模拟语音波动:
class VoiceWaveAnimation extends StatefulWidget { const VoiceWaveAnimation({super.key}); @override State<VoiceWaveAnimation> createState() => _VoiceWaveAnimationState(); } class _VoiceWaveAnimationState extends State<VoiceWaveAnimation> with SingleTickerProviderStateMixin { late AnimationController _controller; final List<double> _waveHeights = List.generate(8, (_) => 0.2); // 初始高度比例 @override void initState() { super.initState(); // 初始化循环动画控制器 _controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 350), )..repeat(); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _controller, builder: (context, child) { // 每帧随机更新部分波形条高度,模拟语音波动 for (int i = 0; i < _waveHeights.length; i++) { if (Random().nextDouble() > 0.6) { _waveHeights[i] = Random().nextDouble() * 0.8 + 0.2; } } return Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: List.generate(_waveHeights.length, (index) { return Container( margin: const EdgeInsets.symmetric(horizontal: 2), width: 4, height: _waveHeights[index] * 30, // 总高度30px,按比例缩放 decoration: BoxDecoration( color: Colors.grey[600], borderRadius: BorderRadius.circular(2), ), ); }), ); }, ); } }
2. 优化流畅度与真实感
- 用
AnimatedBuilder替代全局setState,减少不必要的组件重绘,提升动画流畅度 - 调整动画周期(350ms)和随机更新阈值(0.6),让波动节奏更贴近真实语音的起伏
- 添加透明度和颜色变化,增强视觉层次感:
// 修改AnimatedBuilder内的波形条构建代码 return Opacity( opacity: _waveHeights[index] > 0.5 ? 1.0 : 0.6, child: Container( margin: const EdgeInsets.symmetric(horizontal: 2), width: 4, height: _waveHeights[index] * 30, decoration: BoxDecoration( color: _waveHeights[index] > 0.7 ? Colors.blue : Colors.grey[600], borderRadius: BorderRadius.circular(2), ), ), );
3. 适配语音状态切换
添加控制方法,实现"开始语音-启动动画"、"结束语音-停止并重置动画"的逻辑:
// 在_VoiceWaveAnimationState类中添加 void startAnimation() { if (!_controller.isAnimating) { _controller.repeat(); } } void stopAnimation() { _controller.stop(); setState(() { _waveHeights.fillRange(0, _waveHeights.length, 0.2); // 重置到初始高度 }); }
外部可通过GlobalKey获取组件状态,配合语音按钮的点击/长按事件调用这两个方法。
内容的提问来源于stack exchange,提问作者Devarsh Ukani
相关产品推荐
相关产品推荐

