Framwork/Assets/Scripts/Base/MonoBehaviour/Drag/UIDragHandler.cs

103 lines
3.4 KiB
C#

using UnityEngine;
using UnityEngine.EventSystems;
/// <summary>
/// UI元素拖动处理组件
/// </summary>
[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<RectTransform>();
canvas = GetComponentInParent<Canvas>();
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;
}
}