示例:拖拽Icon
工程截图
UIDragItem.cs
using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
[DisallowMultipleComponent]
public class UIDragItem : UIBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler, IDropHandler
{
public bool interactable = true;
//true: 将拖拽的对象限制在父对象区域内
public bool constraint;
private RectTransform m_RectTransform;
private RectTransform m_ParentTransform;
private Graphic m_Graphic;
private Vector2 localPoint = Vector2.zero;
private Vector2 parentPoint = Vector2.zero;
private Vector2 beginPoint = Vector2.zero;
public class DragEventArgs
{
//被拖拽的对象
public UIDragItem dragItem;
//本地坐标
public Vector2 localPoint;
//外部将此字段设为true,可取消此次拖拽,被拖拽的对象将回到起始位置
public bool endDragCancel;
}
private DragEventArgs dragEventArgs = new DragEventArgs();
[Serializable]
public class EndDragValidateEvent : UnityEvent<DragEventArgs> { }
[FormerlySerializedAs("onEndDragValidate")]
[SerializeField]
private EndDragValidateEvent m_OnEndDragValidate = new EndDragValidateEvent();
[Serializable]
public class EndDragEvent : UnityEvent<DragEventArgs> { }
[FormerlySerializedAs("onEndDrag")]
[SerializeField]
private EndDragEvent m_OnEndDrag = new EndDragEvent();
protected override void Awake()
{
base.Awake();
m_RectTransform = this.GetComponent<RectTransform>();
m_ParentTransform = (RectTransform)m_RectTransform.parent;
m_Graphic = this.GetComponent<Graphic>();
}
public void OnBeginDrag(PointerEventData eventData)
{
if (!interactable)
return;
beginPoint = anchoredPosition;
Vector2 screenPoint = eventData.pressPosition;
RectTransformUtility.ScreenPointToLocalPointInRectangle(m_RectTransform, screenPoint, null, out localPoint);
UpdatePosition();
if (m_Graphic != null)
m_Graphic.raycastTarget = false;
}
public void OnDrag(PointerEventData eventData)
{
if (!interactable)
return;
Vector2 screenPoint = eventData.position;
if (constraint && !RectTransformUtility.RectangleContainsScreenPoint(m_ParentTransform, screenPoint))
return;
RectTransformUtility.ScreenPointToLocalPointInRectangle(m_ParentTransform, screenPoint, null, out parentPoint);
UpdatePosition();
}
public void OnEndDrag(PointerEventData eventData)
{
if (!interactable)
return;
if (m_Graphic != null)
m_Graphic.raycastTarget = true;
dragEventArgs.dragItem = this;
dragEventArgs.localPoint = anchoredPosition;
dragEventArgs.endDragCancel = false;
m_OnEndDragValidate?.Invoke(dragEventArgs);
//如果外部取消了EndDrag行为,将对象重置到起始位置
if (dragEventArgs.endDragCancel)
{
anchoredPosition = beginPoint;
}
else
{
m_OnEndDrag?.Invoke(dragEventArgs);
}
}
//OnDrop在OnEndDrag之前触发
public void OnDrop(PointerEventData eventData)
{
if (!interactable)
return;
}
private void UpdatePosition()
{
anchoredPosition = parentPoint - localPoint;
ConstraintPosition();
}
// 要算法要求父容器的 Pivot=(0.5, 0.5)
private void ConstraintPosition()
{
if (!constraint)
return;
Vector2 parent_size = m_ParentTransform.sizeDelta;
float parentHalfWidth = parent_size.x / 2;
float parentHalfHeight = parent_size.y / 2;
Vector2 size = m_RectTransform.sizeDelta;
float halfWidth = size.x / 2;
float halfHeight = size.y / 2;
Vector2 pos = anchoredPosition;
//约束左侧
float leftEdge = pos.x - halfWidth;
if (leftEdge < -parentHalfWidth)
pos.x = -parentHalfWidth + halfWidth;
//约束右侧
float rightEdge = pos.x + halfWidth;
if (rightEdge > parentHalfWidth)
pos.x = parentHalfWidth - halfWidth;
//约束上侧
float topEdge = pos.y + halfHeight;
if (topEdge > parentHalfHeight)
pos.y = parentHalfHeight - halfHeight;
//约束下侧
float bottomEdge = pos.y - halfHeight;
if (bottomEdge < -parentHalfHeight)
pos.y = -parentHalfHeight + halfHeight;
anchoredPosition = pos;
}
private Vector2 anchoredPosition
{
get { return m_RectTransform.anchoredPosition; }
set { m_RectTransform.anchoredPosition = value; }
}
}
UIDropItem.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
[DisallowMultipleComponent]
public class UIDropItem : UIBehaviour, IDropHandler
{
public void OnDrop(PointerEventData eventData)
{
Debug.Log("OnDrop: " + gameObject.name);
GameObject pointerDrag = eventData.pointerDrag;
if (pointerDrag == null)
return;
Image dragImage = pointerDrag.GetComponent<Image>();
this.GetComponent<Image>().sprite = dragImage.sprite;
}
}
运行测试