如何在Unity 4.6中停止OnBeginDrag()中的拖动事件

11

我有一个脚本,用于处理从给定插槽拖动项目。但我想添加一个停止特定项目拖动的功能。我认为最好的地方是在OnBeginDrag方法中实现,但似乎找不到停止/取消拖动事件本身的方法。以下是我的一部分代码:

public class SlotBehaviour : MonoBehaviour, IDropHandler, IPointerEnterHandler, IPointerExitHandler, IBeginDragHandler, IDragHandler, IEndDragHandler,IPointerClickHandler
{
    public void OnBeginDrag(PointerEventData eventData)
    {
        if (eventData.button != PointerEventData.InputButton.Left)
        {
            return;
        }
        if (this.Empty) return;
        var canvas = imageItem.canvas;
        if (canvas == null) return;
        GUIManager.mouseBusy = true;
        // We have clicked something that can be dragged.
        // What we want to do is create an icon for this.
        m_DraggingIcon = new GameObject("icon");

        m_DraggingIcon.transform.SetParent(canvas.transform, false);
        m_DraggingIcon.transform.SetAsLastSibling();

        var image = m_DraggingIcon.AddComponent<Image>();
        // The icon will be under the cursor.
        // We want it to be ignored by the event system.
        m_DraggingIcon.AddComponent<IgnoreRaycast>();

        image.sprite = imageItem.sprite;
        image.rectTransform.sizeDelta = imageItem.rectTransform.sizeDelta;


        m_DraggingPlane = transform as RectTransform;

        SetDraggedPosition(eventData);

    }

    public void OnDrag(PointerEventData data)
    {
        if (m_DraggingIcon != null)
            SetDraggedPosition(data);
    }

    private void SetDraggedPosition(PointerEventData data)
    {
        if (data.pointerEnter != null && data.pointerEnter.transform as RectTransform != null)
            m_DraggingPlane = data.pointerEnter.transform as RectTransform;

        var rt = m_DraggingIcon.GetComponent<RectTransform>();
        Vector3 globalMousePos;
        if (RectTransformUtility.ScreenPointToWorldPointInRectangle(m_DraggingPlane, data.position, data.pressEventCamera, out globalMousePos))
        {
            rt.position = globalMousePos;
            rt.rotation = m_DraggingPlane.rotation;
        }
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        if (m_DraggingIcon != null)
        {

            Destroy(m_DraggingIcon);
        }
        GUIManager.mouseBusy = false;
        //if you drop it somewhere where its not wanted(or just nowhere)
        if (eventData.used == false)
        {
            if (eventData.pointerCurrentRaycast.gameObject == null)// if its nowhere offer to drop it on ground
            {
                GUIManager.instance.DropItem((int)ItemsDatabase.container[containerID].items[indexInContainer]);
            }
        }
    }
}
我之前尝试返回这个方法,但它没有做任何事情,可能需要处理事件数据...如果你告诉我如何处理它,我将不胜感激。

请注意 - 这里有一个非常完整、优雅的拖放解决方案.. 享受吧 https://dev59.com/oloU5IYBdhLWcg3wamga#37473953 - Fattie
3个回答

49

仅使用 "return" 无法取消任何操作。

相反,您可以修改传递到 OnBeginDrag 函数中的 PointerEventData 信息-具体来说,将 pointerDrag 设置为 null。 这将取消拖动:

eventData.pointerDrag = null;

8
应将此标记为正确答案。关于返回事件方法的其他建议是幼稚的! - Xtro
3
这个答案发布时间正好比被采纳的答案晚了两年,但实际上这是正确的答案。正如所述,将pointerDrag设置为null确实可以防止触发OnDrag和OnEndDrag事件。谢谢! - monkey0506
1
令人沮丧的是,我发现这种情况不起作用 - 我想知道2020年是否存在错误? - Fattie

-1

在2020年似乎无法设置为空值 :/

警告,似乎在2020年无效。 OnDrag 仍然被调用。

这是一个有效的标志解决方案。注意你必须逻辑上使用 mouse-down?但实际上没有其他合理的方法 :/

using UnityEngine;
using UnityEngine.EventSystems;

public class CancellableDragBase : MonoBehaviour,
    IBeginDragHandler, IDragHandler, IEndDragHandler,
    IPointerUpHandler
{
    bool cancelDrag = false;

    public virtual void OnBeginDragCancellable() {}
    public virtual void OnDragCancellable() {}
    public virtual void OnEndDragCancellable() { }

    public void OnBeginDrag(PointerEventData eventData)
    {
        if (cancelDrag)
        {
            return;
        }
        OnBeginDragCancellable();
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (cancelDrag)
        {
            return;
        }
        OnDragCancellable();
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        if (cancelDrag)
        {
            cancelDrag = false;
            return;
        }
        OnEndDragCancellable();
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        if (cancelDrag)
        {
            cancelDrag = false;
            return;
        }
    }

    public void CancelDragIfAny()
    {
        if (Input.GetMouseButton(0))
        {
            cancelDrag = true;
        }
        else
        {
        }
    }
}

真是麻烦。


eventData.pointerDrag = null; 在 2020.1.17f1 中对我有效。 - Dustin Graham
1
@DustinGraham;谢谢……嗯,如果鼠标仍然按下,则在这里肯定不起作用。 ondrag、onenddrag和onpointerup仍然被错误地调用。我会进一步调查! - Fattie

-6

您可以创建标志(例如,IsDragable)。对于您不想拖放的项目,您必须从拖动事件处理程序中返回:

public class DragHangler : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler {

public bool IsDragable;

#region IBeginDragHandler implementation
public void OnBeginDrag (PointerEventData eventData)
{
    if (!IsDragable)    return;

    Debug.Log ("OnBeginDrag:Do something");
}
#endregion

#region IDragHandler implementation

public void OnDrag (PointerEventData eventData)
{
    if (!IsDragable)    return;

    Debug.Log ("OnDrag: Do something");
}

#endregion

#region IEndDragHandler implementation

public void OnEndDrag (PointerEventData eventData)
{
    if (!IsDragable) return;

    Debug.Log ("OnEnd: Do something");
}

#endregion
}

另一种解决方案是在CanvasGroup组件中禁用BlockRaycast。

1
这就是我正在做的事情。但它并不能真正阻止对象的OnDrag和OnEndDrag事件,或者目标上的OnDrop事件。 - Ivan Kuzev
这里没有问题。您可以在OnDrop事件中检查IsDraggable标志。如果为false,则不执行任何操作。 - acoolaum
谢谢!我更喜欢BlockRaycast的方法,因为它还可以禁用所有依赖于拖动事件的触发器(如动画),而DragHandler无法帮助禁用事件并仍然会触发触发器(播放动画)。 - Qorbani
这并没有回答 OP 的问题,它提供了一种规避这些事件仍然被触发的方法。Andrew 的回答 应该被接受,因为它实际上防止了对 OnDrag 和 OnEndDrag 的进一步调用... 所以你 不需要 在其中检查任何标志。 - psycho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接