From bba2f6654685f79b8ebeddd4d4695d457a99e37f Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Fri, 27 Jun 2025 18:48:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(widgets):=20=E6=96=B0=E5=A2=9E=E5=A3=B0?= =?UTF-8?q?=E9=9F=B3=E6=9F=B1=E5=8A=A8=E7=94=BB=E7=BB=84=E4=BB=B6=E5=B9=B6?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E5=8E=9F=E6=9C=89=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将声音柱动画逻辑提取为独立组件SoundBarWidget,并添加组合组件SoundBarsWidget和集成控制器的AgentSoundBarsWidget 移除agent_view中原有的_SoundBar实现,使用新组件替代 --- lib/modules/agent/views/agent_view.dart | 100 +----------- .../agent/widgets/sound_bar_widget.dart | 143 ++++++++++++++++++ 2 files changed, 146 insertions(+), 97 deletions(-) create mode 100644 lib/modules/agent/widgets/sound_bar_widget.dart diff --git a/lib/modules/agent/views/agent_view.dart b/lib/modules/agent/views/agent_view.dart index 5577c6502..a1f8361a2 100644 --- a/lib/modules/agent/views/agent_view.dart +++ b/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 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 with WidgetsBindingObserver { ); } - // 构建声音柱 - Widget _buildSoundBar(int index) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 1), - child: Obx(() => _SoundBar( - delay: index * 0.1, - isActive: Get.find().isListening.value, - )), - ); - } + // 构建"+"号展开选项按钮 Widget _buildPlusOptionButton({ @@ -822,88 +812,4 @@ class _AgentViewState extends State 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 _animation; - - @override - void initState() { - super.initState(); - - _controller = AnimationController( - vsync: this, - duration: const Duration(milliseconds: 500), - ); - - _animation = Tween(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), - ), - ); - } -} diff --git a/lib/modules/agent/widgets/sound_bar_widget.dart b/lib/modules/agent/widgets/sound_bar_widget.dart new file mode 100644 index 000000000..e5c483b36 --- /dev/null +++ b/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 createState() => _SoundBarWidgetState(); +} + +class _SoundBarWidgetState extends State + with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _animation; + + @override + void initState() { + super.initState(); + + _controller = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 500), + ); + + _animation = Tween(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(); + return SoundBarsWidget( + isActive: controller.isListening.value, + barCount: barCount, + ); + }); + } +}