Browse Source

feat(widgets): 新增声音柱动画组件并替换原有实现

将声音柱动画逻辑提取为独立组件SoundBarWidget,并添加组合组件SoundBarsWidget和集成控制器的AgentSoundBarsWidget
移除agent_view中原有的_SoundBar实现,使用新组件替代
weicu
lxm 1 year ago
parent
commit
951e457883
  1. 100
      lib/modules/agent/views/agent_view.dart
  2. 143
      lib/modules/agent/widgets/sound_bar_widget.dart

100
lib/modules/agent/views/agent_view.dart

@ -5,6 +5,7 @@ import '../controllers/agent_controller.dart';
import '../controllers/message_action_controller.dart';
import 'message_bubble.dart';
import '../widgets/full_screen_editor.dart';
import '../widgets/sound_bar_widget.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class AgentView extends StatefulWidget {
@ -486,9 +487,7 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
mainAxisAlignment:
MainAxisAlignment.start,
children: [
...List.generate(10, (index) {
return _buildSoundBar(index);
}),
const AgentSoundBarsWidget(),
const Spacer(),
// "正在聆听"文字
Obx(() {
@ -752,16 +751,7 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
);
}
// 构建声音柱
Widget _buildSoundBar(int index) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 1),
child: Obx(() => _SoundBar(
delay: index * 0.1,
isActive: Get.find<AgentController>().isListening.value,
)),
);
}
// 构建"+"号展开选项按钮
Widget _buildPlusOptionButton({
@ -822,88 +812,4 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
// 声音柱动画组件
class _SoundBar extends StatefulWidget {
final double delay;
final bool isActive;
const _SoundBar({
required this.delay,
required this.isActive,
});
@override
_SoundBarState createState() => _SoundBarState();
}
class _SoundBarState extends State<_SoundBar>
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(_SoundBar 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),
),
);
}
}

143
lib/modules/agent/widgets/sound_bar_widget.dart

@ -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…
Cancel
Save