如何在Flutter应用中实现语音交互动画?
实现Flutter语音状态动态圆形动画方案
一、现成可用的Flutter包
- flutter_sound:核心用于音频录制与播放,可通过其音量监听回调,配合自定义动画组件实现随音量变化的圆形动画。
- animations:官方动画包,提供基础动画组件,能快速构建缩放、渐变的圆形动画,结合语音状态切换触发。
- wave_animation:专注波形动画的包,支持自定义圆形波形样式,可直接关联音频输入的音量数据。
二、自定义实现方案(代码示例)
如果不想依赖第三方包,可完全自定义StatefulWidget实现,核心思路是:监听语音输入的音量变化,根据音量值动态调整圆形的缩放比例、透明度或边框宽度;机器人回复时,用循环的缩放渐变动画模拟加载状态。
自定义语音状态动画组件代码
import 'package:flutter/material.dart'; class VoiceStatusCircle extends StatefulWidget { final bool isUserSpeaking; // 用户是否处于说话状态 final double? volume; // 用户说话时的音量值(范围0-1) final bool isBotResponding; // 机器人是否处于回复状态 const VoiceStatusCircle({ super.key, required this.isUserSpeaking, this.volume, required this.isBotResponding, }); @override State<VoiceStatusCircle> createState() => _VoiceStatusCircleState(); } class _VoiceStatusCircleState extends State<VoiceStatusCircle> with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation<double> _scaleAnimation; @override void initState() { super.initState(); _controller = AnimationController( duration: const Duration(milliseconds: 800), vsync: this, )..repeat(reverse: true); _scaleAnimation = Tween<double>(begin: 0.8, end: 1.2).animate( CurvedAnimation(parent: _controller, curve: Curves.easeInOut), ); } @override void didUpdateWidget(covariant VoiceStatusCircle oldWidget) { super.didUpdateWidget(oldWidget); // 机器人回复状态变化时控制动画播放/暂停 if (widget.isBotResponding != oldWidget.isBotResponding) { if (widget.isBotResponding) { _controller.repeat(reverse: true); } else { _controller.stop(); _controller.value = 0.8; } } } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: Listenable.merge([_controller, widget]), builder: (context, child) { double scale = 1.0; Color circleColor = Colors.grey.shade300; if (widget.isUserSpeaking && widget.volume != null) { // 用户说话时,根据音量调整缩放比例 scale = 0.8 + (widget.volume! * 0.4); circleColor = Colors.blue.shade400; } else if (widget.isBotResponding) { // 机器人回复时使用循环缩放动画 scale = _scaleAnimation.value; circleColor = Colors.green.shade400; } return Transform.scale( scale: scale, child: Container( width: 60, height: 60, decoration: BoxDecoration( color: circleColor.withOpacity(0.6), shape: BoxShape.circle, border: Border.all( color: circleColor, width: widget.isUserSpeaking ? 2 + (widget.volume! * 2) : 2, ), ), child: Center( child: Icon( widget.isUserSpeaking ? Icons.mic : Icons.speaker, color: Colors.white, ), ), ), ); }, ); } }
使用示例
// 在页面中引入组件 VoiceStatusCircle( isUserSpeaking: _isRecording, // 你的录制状态变量 volume: _currentVolume, // 从音频插件获取的音量值(范围0-1) isBotResponding: _isBotReplying, // 机器人回复状态变量 )
三、实现关键点说明
- 音量监听:若使用
flutter_sound,可通过RecorderController的onProgress回调获取当前音量,转换为0-1的范围传入组件。 - 状态切换:在用户停止说话、机器人开始/结束回复时,需正确更新组件的状态参数,触发动画变化。
- 性能优化:使用
AnimatedBuilder和SingleTickerProviderStateMixin避免不必要的重绘,保证动画流畅。
内容的提问来源于stack exchange,提问作者Pritesh Gujarati
相关产品推荐
相关产品推荐

