Browse Source
将声音柱动画逻辑提取为独立组件SoundBarWidget,并添加组合组件SoundBarsWidget和集成控制器的AgentSoundBarsWidget 移除agent_view中原有的_SoundBar实现,使用新组件替代weicu
2 changed files with 146 additions and 97 deletions
@ -0,0 +1,143 @@ |
|||
import 'package:flutter/material.dart'; |
|||
import 'package:get/get.dart'; |
|||
import '../controllers/agent_controller.dart'; |
|||
|
|||
/// 声音柱动画组件 |
|||
/// 用于显示语音输入时的音频波形效果 |
|||
class SoundBarWidget extends StatefulWidget { |
|||
final double delay; |
|||
final bool isActive; |
|||
|
|||
const SoundBarWidget({ |
|||
Key? key, |
|||
required this.delay, |
|||
required this.isActive, |
|||
}) : super(key: key); |
|||
|
|||
@override |
|||
State<SoundBarWidget> createState() => _SoundBarWidgetState(); |
|||
} |
|||
|
|||
class _SoundBarWidgetState extends State<SoundBarWidget> |
|||
with SingleTickerProviderStateMixin { |
|||
late AnimationController _controller; |
|||
late Animation<double> _animation; |
|||
|
|||
@override |
|||
void initState() { |
|||
super.initState(); |
|||
|
|||
_controller = AnimationController( |
|||
vsync: this, |
|||
duration: const Duration(milliseconds: 500), |
|||
); |
|||
|
|||
_animation = Tween<double>(begin: 3, end: 18).animate( |
|||
CurvedAnimation( |
|||
parent: _controller, |
|||
curve: Curves.easeInOut, |
|||
), |
|||
)..addListener(() { |
|||
setState(() {}); |
|||
}); |
|||
|
|||
_startOrStopAnimation(); |
|||
} |
|||
|
|||
@override |
|||
void didUpdateWidget(SoundBarWidget oldWidget) { |
|||
super.didUpdateWidget(oldWidget); |
|||
if (widget.isActive != oldWidget.isActive) { |
|||
_startOrStopAnimation(); |
|||
} |
|||
} |
|||
|
|||
/// 开始或停止动画 |
|||
void _startOrStopAnimation() { |
|||
if (widget.isActive) { |
|||
Future.delayed(Duration(milliseconds: (widget.delay * 1000).toInt()), () { |
|||
if (mounted && widget.isActive) { |
|||
_controller.repeat(reverse: true); |
|||
} |
|||
}); |
|||
} else { |
|||
_controller.reset(); |
|||
// 设置为小高度的静态状态 |
|||
_controller.animateTo(0.1, duration: const Duration(milliseconds: 300)); |
|||
} |
|||
} |
|||
|
|||
@override |
|||
void dispose() { |
|||
_controller.dispose(); |
|||
super.dispose(); |
|||
} |
|||
|
|||
@override |
|||
Widget build(BuildContext context) { |
|||
final primaryColor = Theme.of(context).primaryColor; |
|||
|
|||
return Container( |
|||
width: 2.5, |
|||
height: widget.isActive ? _animation.value : 3, |
|||
margin: const EdgeInsets.symmetric(horizontal: 1), |
|||
decoration: BoxDecoration( |
|||
color: widget.isActive |
|||
? primaryColor.withOpacity(0.8) |
|||
: Colors.grey.withOpacity(0.4), |
|||
borderRadius: BorderRadius.circular(1.5), |
|||
), |
|||
); |
|||
} |
|||
} |
|||
|
|||
/// 声音柱组合组件 |
|||
/// 包含多个声音柱的组合显示 |
|||
class SoundBarsWidget extends StatelessWidget { |
|||
final bool isActive; |
|||
final int barCount; |
|||
|
|||
const SoundBarsWidget({ |
|||
Key? key, |
|||
required this.isActive, |
|||
this.barCount = 10, |
|||
}) : super(key: key); |
|||
|
|||
@override |
|||
Widget build(BuildContext context) { |
|||
return Row( |
|||
mainAxisAlignment: MainAxisAlignment.start, |
|||
children: List.generate(barCount, (index) { |
|||
return Padding( |
|||
padding: const EdgeInsets.symmetric(horizontal: 1), |
|||
child: SoundBarWidget( |
|||
delay: index * 0.1, |
|||
isActive: isActive, |
|||
), |
|||
); |
|||
}), |
|||
); |
|||
} |
|||
} |
|||
|
|||
/// 带控制器集成的声音柱组件 |
|||
/// 自动从AgentController获取状态 |
|||
class AgentSoundBarsWidget extends StatelessWidget { |
|||
final int barCount; |
|||
|
|||
const AgentSoundBarsWidget({ |
|||
Key? key, |
|||
this.barCount = 10, |
|||
}) : super(key: key); |
|||
|
|||
@override |
|||
Widget build(BuildContext context) { |
|||
return Obx(() { |
|||
final controller = Get.find<AgentController>(); |
|||
return SoundBarsWidget( |
|||
isActive: controller.isListening.value, |
|||
barCount: barCount, |
|||
); |
|||
}); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue