103 lines
3.4 KiB
C#
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;
|
|
}
|
|
} |