UI Toolkitで長押しできるButtonを作成【エディタ拡張】

UIElementsのButtonを継承した、長押しを検知できるLongClickButtonを作成しました。

指定した秒数以上長押しした場合、その秒数経った瞬間にActionを実行します。

指定した秒数未満でボタンを離した場合に実行する、通常Actionも必要に応じて指定できます。

using System;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

/// <summary>
/// 長押しイベントを設定できるButton
/// </summary>
public class LongClickButton : Button
{
    private bool _isLongClicked; // 長押し済みか
    private float _buttonDownTime; // ボタンを押した時間
    private readonly float _durationForLongClick; // 長押しと判断する秒数
    private readonly Action _longClickEvent; // 長押し時のイベント

    /// <summary>
    /// コンストラクタ
    /// </summary>
    /// <param name="durationForLongClick">長押しと判定する秒数</param>
    /// <param name="longClickEvent">durationForLongClickを過ぎた時のイベント</param>
    /// <param name="normalClickEvent">durationForLongClickを過ぎずに離した時の通常クリックイベント</param>
    public LongClickButton(float durationForLongClick, Action longClickEvent, Action normalClickEvent = null)
    {
        _durationForLongClick = durationForLongClick;
        _longClickEvent = longClickEvent;

        // ButtonはMouseDownEventを受け取れないので、その子要素にMouseDownEventを受け取るVisualElementを作成
        var buttonEventTarget = new VisualElement();
        Add(buttonEventTarget);
        buttonEventTarget.StretchToParentSize();

        // Down時の処理を設定
        buttonEventTarget.RegisterCallback<MouseDownEvent>(_ =>
        {
            _isLongClicked = false;
            _buttonDownTime = Time.realtimeSinceStartup;
            EditorApplication.update += OnUpdate;
        });

        // Up時の処理を設定
        RegisterCallback<MouseUpEvent>(_ =>
        {
            EditorApplication.update -= OnUpdate;
            if (!_isLongClicked)
            {
                normalClickEvent?.Invoke();
            }
        });
    }

    private void OnUpdate()
    {
        if (_isLongClicked)
        {
            return;
        }

        var isLongClick = Time.realtimeSinceStartup - _buttonDownTime >= _durationForLongClick;
        if (isLongClick)
        {
            _longClickEvent?.Invoke();
            _isLongClicked = true;
        }
    }
}

 

MouseDownEventはButtonが競合してしまうようで、そのままButtonにMouseDownEventを設定しようとしても反応しませんでした。

そのためMouseDownEventを検知する用の空VisualElementを追加し、それに対してMouseDownEventを設定しています。

 

呼び出し方の例です。

using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

public class TestWindow : EditorWindow
{
    [MenuItem("Window/TestWindow")]
    public static void Open()
    {
        var window = GetWindow<TestWindow>();
        window.Show();
    }

    private void OnEnable()
    {
        var longClickButton = new LongClickButton(0.5f, () => Debug.Log("LongClicked"), () => Debug.Log("NormalClicked"))
        {
            text = "LongClickButton",
            style = { width = 200, height = 60, alignSelf = Align.Center }
        };
        rootVisualElement.Add(longClickButton);
    }
}

コメント