鸟语天空
UGUI—Drag与Drop
post by:追风剑情 2019-10-21 15:56

示例:拖拽Icon

工程截图

1111.png

2222.png

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;
    }
}


运行测试

5555.gif

评论:
发表评论:
昵称

邮件地址 (选填)

个人主页 (选填)

内容