示例:拖拽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; } }
运行测试