using UnityEngine; using UnityEngine.EventSystems; /// /// UI元素拖动处理组件 /// [RequireComponent(typeof(RectTransform))] public class UIDragHandler : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler { [Header("拖动设置")] [SerializeField] private bool restrictToParent = true; [SerializeField] private bool enableSmoothDrag = true; [SerializeField] private float smoothSpeed = 0.2f; [Header("事件回调")] public UnityEngine.Events.UnityEvent onDragBegin; public UnityEngine.Events.UnityEvent onDrag; public UnityEngine.Events.UnityEvent onDragEnd; private RectTransform rectTransform; private RectTransform parentRectTransform; private Canvas canvas; private Vector2 offset = Vector2.zero; private Vector3 targetPosition; private bool isDragging = false; private void Awake() { rectTransform = GetComponent(); canvas = GetComponentInParent(); parentRectTransform = rectTransform.parent as RectTransform; } public void OnBeginDrag(PointerEventData eventData) { // 计算鼠标与UI元素的偏移量 RectTransformUtility.ScreenPointToLocalPointInRectangle( rectTransform, eventData.position, canvas.worldCamera, out offset); isDragging = true; onDragBegin?.Invoke(); } public void OnDrag(PointerEventData eventData) { if (canvas == null) return; // 将鼠标屏幕坐标转换为Canvas中的局部坐标 if (RectTransformUtility.ScreenPointToLocalPointInRectangle( parentRectTransform, eventData.position, canvas.worldCamera, out Vector2 localPoint)) { // 应用偏移量并设置位置 targetPosition = parentRectTransform.TransformPoint(localPoint - offset); // 边界限制 if (restrictToParent && parentRectTransform != null) { targetPosition = RestrictPositionToParent(targetPosition); } // 平滑拖动或直接设置位置 if (enableSmoothDrag) { rectTransform.position = Vector3.Lerp(rectTransform.position, targetPosition, smoothSpeed); } else { rectTransform.position = targetPosition; } } onDrag?.Invoke(); } public void OnEndDrag(PointerEventData eventData) { isDragging = false; onDragEnd?.Invoke(); } private Vector3 RestrictPositionToParent(Vector3 position) { Vector3 clampedPosition = position; if (parentRectTransform != null) { // 获取父容器的边界 Vector2 parentSize = parentRectTransform.sizeDelta; Vector2 min = -parentSize * parentRectTransform.pivot; Vector2 max = parentSize * (Vector2.one - parentRectTransform.pivot); // 获取当前UI元素的边界 Vector2 size = rectTransform.sizeDelta; Vector2 halfSize = size * 0.5f; // 计算限制后的位置 clampedPosition.x = Mathf.Clamp(clampedPosition.x, min.x + halfSize.x, max.x - halfSize.x); clampedPosition.y = Mathf.Clamp(clampedPosition.y, min.y + halfSize.y, max.y - halfSize.y); } return clampedPosition; } }