From ab7f02e77e62c548bf1a7f84421189e4b17a1c79 Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Mon, 22 Sep 2025 16:54:31 +0800 Subject: [PATCH] =?UTF-8?q?refactor(translation):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E7=BF=BB=E8=AF=91=E6=A8=A1=E5=BC=8F=E9=80=89=E6=8B=A9=E5=99=A8?= =?UTF-8?q?=E7=9A=84=E6=98=BE=E7=A4=BA=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除手动计算锚点的冗余代码,统一从悬浮按钮位置展开 优化选择器动画和背景处理,提升用户体验 --- .../controllers/translation_controller.dart | 24 +++++++ .../dialogs/translation_mode_selector.dart | 68 +++++++++++-------- .../translation/views/translation_view.dart | 18 ++--- .../widgets/draggable_floating_button.dart | 10 +-- 4 files changed, 74 insertions(+), 46 deletions(-) diff --git a/lib/modules/translation/controllers/translation_controller.dart b/lib/modules/translation/controllers/translation_controller.dart index cfb187c98..9b0ee6374 100644 --- a/lib/modules/translation/controllers/translation_controller.dart +++ b/lib/modules/translation/controllers/translation_controller.dart @@ -23,6 +23,7 @@ import '../../../data/services/ble_manager.dart'; import 'record_timer_controller.dart'; import 'translation_history_controller.dart'; import '../models/translation_models.dart'; +import '../views/dialogs/translation_mode_selector.dart'; /// 音频输出设备枚举 enum AudioOutputDevice { @@ -285,6 +286,17 @@ class TranslationController extends GetxController with WidgetsBindingObserver { // 监听应用生命周期:当应用切到后台/失焦时兜底重置 activeSpeaker WidgetsBinding.instance.addObserver(this); + + // 延迟显示模式选择器,确保页面已经完全加载 + // Future.delayed(const Duration(milliseconds: 100), () { + // _showModeSelector(); + // }); + //确保关键服务初始化完成 + WidgetsBinding.instance.addPostFrameCallback((_) async { + // 确保上下文有效 + if (Get.context == null || !Get.context!.mounted) return; + _showModeSelector(); + }); } /// 预先检查权限 @@ -339,6 +351,18 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } + /// 显示模式选择器 + void _showModeSelector() { + try { + final isDarkMode = Get.theme.brightness == Brightness.dark; + + // 直接使用现有的翻译模式选择器组件 + TranslationModeSelector.show(isDarkMode); + } catch (e) { + Logger.error('显示模式选择器失败: $e'); + } + } + /// 保存悬浮按钮位置 void saveFloatingButtonPosition(Offset position) { floatingButtonPosition.value = position; diff --git a/lib/modules/translation/views/dialogs/translation_mode_selector.dart b/lib/modules/translation/views/dialogs/translation_mode_selector.dart index c9d4ed3c7..a1fe0f0f6 100644 --- a/lib/modules/translation/views/dialogs/translation_mode_selector.dart +++ b/lib/modules/translation/views/dialogs/translation_mode_selector.dart @@ -11,20 +11,25 @@ class TranslationModeSelector { static void show(bool isDarkMode, {Offset? anchor}) { final controller = Get.find(); - // 计算缩放对齐点(-1..1)。如果未提供 anchor,则从底部中间展开 - Alignment alignment = Alignment.bottomCenter; - if (anchor != null) { - final Size screenSize = MediaQuery.of(Get.context!).size; - final double ax = (anchor.dx / screenSize.width) * 2 - 1; - final double ay = (anchor.dy / screenSize.height) * 2 - 1; - alignment = Alignment(ax, ay); - } + // 总是从悬浮按钮位置展开,不依赖传入的anchor参数 + final Size screenSize = MediaQuery.of(Get.context!).size; + final Offset floatingButtonPos = controller.floatingButtonPosition.value; + + // 计算悬浮按钮的中心点位置(从右下角偏移转换为屏幕坐标) + final double buttonSize = 56.0; // 悬浮按钮的大小 + final double buttonCenterX = screenSize.width - floatingButtonPos.dx - buttonSize / 2; + final double buttonCenterY = screenSize.height - floatingButtonPos.dy - buttonSize / 2; + + // 计算缩放对齐点(-1..1) + final double ax = (buttonCenterX / screenSize.width) * 2 - 1; + final double ay = (buttonCenterY / screenSize.height) * 2 - 1; + final Alignment alignment = Alignment(ax, ay); Get.generalDialog( barrierLabel: 'translation_mode_selector', - barrierDismissible: true, - barrierColor: Colors.black.withOpacity(0.35), - transitionDuration: const Duration(milliseconds: 250), + barrierDismissible: true, // 允许点击背景关闭 + barrierColor: Colors.transparent, // 设置为透明,让自定义模糊层处理点击 + transitionDuration: const Duration(milliseconds: 300), pageBuilder: (context, animation, secondaryAnimation) { return const SizedBox.shrink(); }, @@ -35,17 +40,22 @@ class TranslationModeSelector { reverseCurve: Curves.easeInCubic); return Stack( children: [ - // 模糊背景 - Positioned.fill( + // 修复:将模糊背景放在可点击区域 + GestureDetector( + onTap: () => Get.back(), // 添加点击关闭功能 child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), - child: Container(color: Colors.transparent), + child: Container( + color: isDarkMode + ? Colors.black.withOpacity(0.55) + : Colors.grey.withOpacity(0.95), // 添加半透明背景 + ), ), ), - // 将缩放应用在一个全屏容器上,以便 alignment 以屏幕为参考 + // 内容区域 ScaleTransition( alignment: alignment, - scale: Tween(begin: 0.0, end: 1.0).animate(curved), + scale: Tween(begin: 0.1, end: 1.0).animate(curved), child: FadeTransition( opacity: curved, child: SizedBox.expand( @@ -127,19 +137,19 @@ class TranslationModeSelector { } : null, ), - SizedBox(height: 24.w), - GestureDetector( - onTap: () => Get.back(), - child: Container( - width: 42, - height: 42, - decoration: BoxDecoration( - color: Colors.black.withValues(alpha: 0.8), - borderRadius: BorderRadius.circular(50), - ), - child: const Icon(Icons.close, color: Colors.white), - ), - ), + SizedBox(height: 64.w), + // GestureDetector( + // onTap: () => Get.back(), + // child: Container( + // width: 42, + // height: 42, + // decoration: BoxDecoration( + // color: Colors.black.withValues(alpha: 0.8), + // borderRadius: BorderRadius.circular(50), + // ), + // child: const Icon(Icons.close, color: Colors.white), + // ), + // ), if (Platform.isAndroid) SizedBox(height: 20.h), ], ), diff --git a/lib/modules/translation/views/translation_view.dart b/lib/modules/translation/views/translation_view.dart index a9a792433..b7fc30206 100644 --- a/lib/modules/translation/views/translation_view.dart +++ b/lib/modules/translation/views/translation_view.dart @@ -145,15 +145,15 @@ class TranslationView extends GetView { onTap: () { // 点击标题时弹出翻译模式选择器 // 从拖拽按钮位置作为锚点打开 - final pos = controller.floatingButtonPosition.value; - final Size screen = MediaQuery.of(Get.context!).size; - // 已保存的是距右、下的偏移,需要换算为屏幕坐标中的中心点 - final double buttonSize = 56.w; - final double left = screen.width - pos.dx - buttonSize; - final double top = screen.height - pos.dy - buttonSize; - final Offset anchor = - Offset(left + buttonSize / 2, top + buttonSize / 2); - TranslationModeSelector.show(isDarkMode, anchor: anchor); + // final pos = controller.floatingButtonPosition.value; + // final Size screen = MediaQuery.of(Get.context!).size; + // // 已保存的是距右、下的偏移,需要换算为屏幕坐标中的中心点 + // final double buttonSize = 56.w; + // final double left = screen.width - pos.dx - buttonSize; + // final double top = screen.height - pos.dy - buttonSize; + // final Offset anchor = + // Offset(left + buttonSize / 2, top + buttonSize / 2); + TranslationModeSelector.show(isDarkMode); }, child: Text( controller.currentModeTitle.value.tr, diff --git a/lib/modules/translation/views/widgets/draggable_floating_button.dart b/lib/modules/translation/views/widgets/draggable_floating_button.dart index bef3dbef1..9c4935a21 100644 --- a/lib/modules/translation/views/widgets/draggable_floating_button.dart +++ b/lib/modules/translation/views/widgets/draggable_floating_button.dart @@ -108,13 +108,7 @@ class DraggableFloatingButton extends StatelessWidget { /// 显示翻译模式选择器 void _showTranslationModeSelector(bool isDarkMode) { - // 使用保存的位置换算按钮中心点(与标题点击一致) - final pos = controller.floatingButtonPosition.value; // 距右、下的偏移 - final Size screen = MediaQuery.of(Get.context!).size; - final double buttonSize = 56.w; - final double left = screen.width - pos.dx - buttonSize; - final double top = screen.height - pos.dy - buttonSize; - final Offset anchor = Offset(left + buttonSize / 2, top + buttonSize / 2); - TranslationModeSelector.show(isDarkMode, anchor: anchor); + // 直接调用模式选择器,它会自动从悬浮按钮位置展开 + TranslationModeSelector.show(isDarkMode); } }