You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

113 lines
3.9 KiB

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../controllers/translation_controller.dart';
import '../dialogs/translation_mode_selector.dart';
/// 可拖拽悬浮按钮组件
class DraggableFloatingButton extends StatelessWidget {
final bool isDarkMode;
final TranslationController controller;
const DraggableFloatingButton({
Key? key,
required this.isDarkMode,
required this.controller,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Obx(() => Positioned(
right: controller.floatingButtonPosition.value.dx, // 使用保存的位置
bottom: controller.floatingButtonPosition.value.dy, // 使用保存的位置
child: Draggable(
feedback: Material(
color: Colors.transparent,
child: Container(
width: 56.w,
height: 56.w,
decoration: BoxDecoration(
color: (isDarkMode ? Colors.grey[700] : Colors.blue)
?.withOpacity(0.8),
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.3),
blurRadius: 8,
offset: const Offset(0, 4),
),
],
),
child: Icon(
Icons.translate,
color: Colors.white,
size: 24.sp,
),
),
),
childWhenDragging: Container(
width: 56.w,
height: 56.w,
decoration: BoxDecoration(
color: (isDarkMode ? Colors.grey[700] : Colors.blue)
?.withOpacity(0.3),
shape: BoxShape.circle,
),
),
onDragEnd: (details) {
_handleDragEnd(context, details);
},
child: GestureDetector(
onTap: () => _showTranslationModeSelector(isDarkMode),
child: Container(
width: 56.w,
height: 56.w,
decoration: BoxDecoration(
color: isDarkMode ? Colors.grey[700] : Colors.blue,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 6,
offset: const Offset(0, 3),
),
],
),
child: Icon(
Icons.translate,
color: Colors.white,
size: 24.sp,
),
),
),
),
));
}
/// 处理拖拽结束事件
void _handleDragEnd(BuildContext context, DraggableDetails details) {
final screenSize = MediaQuery.of(context).size;
final appBarHeight = Scaffold.of(context).appBarMaxHeight ?? kToolbarHeight;
final statusBarHeight = MediaQuery.of(context).padding.top;
final safeAreaTop = statusBarHeight + appBarHeight;
// 计算新位置(相对于屏幕右下角)
final newRight = screenSize.width - details.offset.dx - 56.w;
final newBottom = screenSize.height - details.offset.dy - 56.w;
// 边界检查,确保按钮不会超出屏幕或被AppBar遮盖
final clampedRight = newRight.clamp(0.0, screenSize.width - 56.w);
final clampedBottom = newBottom.clamp(
0.0, // 底部边界
screenSize.height - safeAreaTop - 56.w, // 顶部边界(避免被AppBar遮盖)
);
// 保存新位置
controller.saveFloatingButtonPosition(Offset(clampedRight, clampedBottom));
}
/// 显示翻译模式选择器
void _showTranslationModeSelector(bool isDarkMode) {
TranslationModeSelector.show(isDarkMode);
}
}