diff --git a/lib/modules/translation/views/dialogs/translation_mode_selector.dart b/lib/modules/translation/views/dialogs/translation_mode_selector.dart index 9a5b94489..c9d4ed3c7 100644 --- a/lib/modules/translation/views/dialogs/translation_mode_selector.dart +++ b/lib/modules/translation/views/dialogs/translation_mode_selector.dart @@ -8,16 +8,57 @@ import '../../controllers/translation_controller.dart'; /// 翻译模式选择对话框 class TranslationModeSelector { /// 显示翻译模式选择器 - static void show(bool isDarkMode) { + static void show(bool isDarkMode, {Offset? anchor}) { final controller = Get.find(); - Get.bottomSheet( - BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), - child: _buildTranslationModeSelector(controller), - ), - isScrollControlled: true, - backgroundColor: Colors.transparent, + // 计算缩放对齐点(-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); + } + + Get.generalDialog( + barrierLabel: 'translation_mode_selector', + barrierDismissible: true, + barrierColor: Colors.black.withOpacity(0.35), + transitionDuration: const Duration(milliseconds: 250), + pageBuilder: (context, animation, secondaryAnimation) { + return const SizedBox.shrink(); + }, + transitionBuilder: (context, animation, secondaryAnimation, child) { + final curved = CurvedAnimation( + parent: animation, + curve: Curves.easeOutCubic, + reverseCurve: Curves.easeInCubic); + return Stack( + children: [ + // 模糊背景 + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), + child: Container(color: Colors.transparent), + ), + ), + // 将缩放应用在一个全屏容器上,以便 alignment 以屏幕为参考 + ScaleTransition( + alignment: alignment, + scale: Tween(begin: 0.0, end: 1.0).animate(curved), + child: FadeTransition( + opacity: curved, + child: SizedBox.expand( + child: Align( + alignment: Alignment.bottomCenter, + child: _buildTranslationModeSelector(controller), + ), + ), + ), + ), + ], + ); + }, ); } diff --git a/lib/modules/translation/views/translation_view.dart b/lib/modules/translation/views/translation_view.dart index e3bc1fc0c..a9a792433 100644 --- a/lib/modules/translation/views/translation_view.dart +++ b/lib/modules/translation/views/translation_view.dart @@ -144,7 +144,16 @@ class TranslationView extends GetView { title: Obx(() => GestureDetector( onTap: () { // 点击标题时弹出翻译模式选择器 - TranslationModeSelector.show(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); }, 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 80fa508f0..bef3dbef1 100644 --- a/lib/modules/translation/views/widgets/draggable_floating_button.dart +++ b/lib/modules/translation/views/widgets/draggable_floating_button.dart @@ -108,6 +108,13 @@ class DraggableFloatingButton extends StatelessWidget { /// 显示翻译模式选择器 void _showTranslationModeSelector(bool isDarkMode) { - TranslationModeSelector.show(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); } }