【Unity】【UI Toolkit】Unityエディタ上でドラッグ&ドロップをハンドリングするイベントまとめ

UnityのUI Toolkitで、Unityエディタ上でドラッグ&ドロップをハンドリングするイベントについてまとめました。

Unity 2022.2.19

ドラッグ&ドロップをハンドリングするイベント

UI Toolkitには、UIに対してドラッグ&ドロップが行われたことを通知するためのイベントが用意されています。
用意されているイベントは以下の通りです。

  • DragEnterEvent: ドラッグされた状態のカーソルがUIの領域に入ってきた時のイベント
  • DragLeaveEvent: ドラッグされた状態のカーソルがUIの領域から出た時のイベント
  • DragUpdatedEvent: ドラッグされた状態のカーソルがUIの領域に入っている間呼ばれる
  • DragPerformEvent: ドラッグされたものがUIの領域上でドロップされたときに呼ばれる
  • DragExitedEvent: ドラッグ&ドロップの処理が終わった時に呼ばれるイベント

これらを使うことで、たとえば独自のEditorWindowにアセットをドラッグ&ドロップした時の処理や、独自のEditorWindow間のドラッグ&ドロップの処理などを記述できます。

本記事ではこのイベントの使い方についてまとめます。

なおこのイベントについてはUnityEditor上でのみ動作するものなのでその点ご注意ください。

ドラッグ&ドロップされた時の処理を実装する

それでは実際にドラッグ&ドロップされた時の処理を実装してみます。
今回は以下のように、EditorWindow上に赤い四角形を作成し、それに対してドラッグ&ドロップのイベントを登録しています。

using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

public sealed class ExampleWindow : EditorWindow
{
    private void CreateGUI()
    {
        // 適当に赤い四角を作る
        var droppable = new VisualElement();
        droppable.style.width = 100;
        droppable.style.height = 100;
        droppable.style.backgroundColor = Color.red;

        // 各種ドラッグイベントを登録する
        droppable.RegisterCallback<DragEnterEvent>(OnDragEnter);
        droppable.RegisterCallback<DragLeaveEvent>(OnDragLeave);
        droppable.RegisterCallback<DragUpdatedEvent>(OnDragUpdate);
        droppable.RegisterCallback<DragPerformEvent>(OnDragPerform);
        droppable.RegisterCallback<DragExitedEvent>(OnDragExited);

        rootVisualElement.Add(droppable);
    }

    private void OnDragEnter(DragEnterEvent evt)
    {
        Debug.Log("ドラッグされたものが入ってきた時の処理");
    }

    private void OnDragLeave(DragLeaveEvent evt)
    {
        Debug.Log("ドラッグされたものが出ていった時の処理");
    }

    private void OnDragUpdate(DragUpdatedEvent evt)
    {
        // ドラッグ中の処理
        DragAndDrop.visualMode = DragAndDropVisualMode.Copy; // ドラッグ中はカーソルのアイコンを変える
    }

    private void OnDragPerform(DragPerformEvent evt)
    {
        Debug.Log("ドロップされた時の処理");

        // ドロップを受け入れる
        DragAndDrop.AcceptDrag();

        // ProjectウィンドウからアセットをD&Dしたり、Unity外からファイルをD&Dしたりしたらpathsにファイルパスが入ってくる
        foreach (var path in DragAndDrop.paths)
            Debug.Log(path);

        // シーンからオブジェクトをD&Dしたり、ProjectウィンドウからアセットをD&DしたらobjectReferencesにオブジェクトが入ってくる
        foreach (var obj in DragAndDrop.objectReferences)
            Debug.Log(obj);

        // DragAndDrop.SetGenericDataで設定したデータを取得する
        var genericData = DragAndDrop.GetGenericData("test");
        Debug.Log(genericData);
    }

    private void OnDragExited(DragExitedEvent evt)
    {
        Debug.Log("ドラッグ&ドロップの処理が終了した時の処理");
    }

    [MenuItem("Window/Example")]
    private static void Open()
    {
        GetWindow<ExampleWindow>();
    }
}

説明はコメントに記載しました。
上の実装のように、DragAndDropクラスを組み合わせて使用します(このクラスはUI ToolkitのクラスではなくUnityエディタとして実装されているクラスです)。

動作確認

次に前節で実装したウィンドウの動作確認を行います。
Window > Exampleからウィンドウを開くと以下のようなウィンドウが表示されます。

動作確認

この赤い矩形に対してProjectウィンドウから任意のアセットをドラッグ&ドロップすると、各種ログがConsoleウィンドウに出力されることを確認できます。

ドラッグ開始処理を書く

本記事のイベントとは直接関係ありませんが、関連する内容として、以下のようにすると自身でドラッグを開始する処理を書くこともできます。
ファイルなど以外に任意のオブジェクトをドラッグ&ドロップさせたい場合にはこれを使用します。

var startPoint = new VisualElement();
startPoint.style.width = 100;
startPoint.style.height = 100;
startPoint.style.backgroundColor = Color.blue;
startPoint.RegisterCallback<PointerDownEvent>(_ =>
{
    // データをセットしたりStartDragする前にこれを呼ぶ
    DragAndDrop.PrepareStartDrag();

    // ドロップ先に受け渡したい情報を入力
    DragAndDrop.SetGenericData("key", "drag and drop test");

    // オブジェクトやパスも受け渡せる
    //DragAndDrop.objectReferences = new[] {  };
    //DragAndDrop.paths = new string[] { };

    // ドラッグ開始
    DragAndDrop.StartDrag(string.Empty);
});
rootVisualElement.Add(startPoint);

参考

docs.unity3d.com