[Unity Case] Double click and long press of Button

Implementation content:

Extend Unity's own Button component to achieve double-click and long-press effects based on the original click event;

Replace the Button component and select which event is currently executed through the radio button
Replace the Button component and select which event is currently executed through the radio button

Detailed code explanation:

  1. Click event handling:
    • Control whether to enable click events throughsingleClickEnabled switch.
    • InOnPointerClick method, execute the click event according to the activation state and interactable state of the button.
    • Use Unity's Profiler API to add markers and trigger the button's click event callback.
  2. Double-click event handling:
    • Control whether to enable double-click events throughdoubleClickEnabled switch.
    • InOnPointerClick method, record the number of clicks and determine whether to trigger a double-click event based on the double-click time threshold.
    • If a double-click is detected, add a Profiler tag, trigger the double-click event callback, and reset the click count.
  3. Long press event handling:
    • Control whether to enable long press events throughlongPressEnabled switch.
    • InOnPointerDown method, record the press time and mark the long press state.
    • InOnPointerUp method, reset the long press state.
    • UseUpdate method to detect long press regularly. If the long press time threshold is reached, the long press event callback is triggered.
  4. Event callback:
    • Use ButtonClickedEvent type of event callback, which can be configured in the Inspector.
    • Provides event callbacks for click, double-click and long press, which can be set through the Inspector or code.

The complete code is as follows:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
using UnityEngine.UI;

public class ButtonExtension : Button
{
    #region 单机双击相关

    public bool singleClickEnabled = true;
    public bool doubleClickEnabled = false;
    public float doubleClickTime = 0.3f;
    
    private float lastClickTime = float.NegativeInfinity;
    private int clickCount = 0;
    
    [FormerlySerializedAs("onDoubleClick")]
    [SerializeField]
    private ButtonClickedEvent doubleClickEvent = new ();
    
    public ButtonClickedEvent onDoubleClick
    {
        get => doubleClickEvent;
        set => doubleClickEvent = value;
    }

    public override void OnPointerClick(PointerEventData eventData)
    {
        if(!IsActive() && !interactable) 
            return;

        if (singleClickEnabled)
        {
            UISystemProfilerApi.AddMarker("Button.onClick", this);
            onClick?.Invoke();
            Debug.LogError("单击");   
        }

        if (doubleClickEnabled)
        {
            clickCount++;
            if (clickCount >= 2)
            {
                if (Time.realtimeSinceStartup - lastClickTime < doubleClickTime)
                {
                    UISystemProfilerApi.AddMarker("Button.onDoubleClick", this);
                    onDoubleClick?.Invoke();
                    Debug.LogError("双击");
                    lastClickTime = float.NegativeInfinity;
                    clickCount = 0;   
                }
                else
                {
                    clickCount = 1;
                    lastClickTime = Time.unscaledTime;
                }
            }
            else
            {
                lastClickTime = Time.unscaledTime;
            }
        }
    }

    #endregion

    #region 长按相关

    public bool longPressEnabled = false;

    private float lastPressTime = 0;
    
    public float minPressTime = 0.5f;

    private bool isPressing = false;
    
    private bool hasInvokedLongPress = false;

    [FormerlySerializedAs("onLongPress")]
    [SerializeField]
    private ButtonClickedEvent longPressEvent = new();
    
    public ButtonClickedEvent onLongPress
    {
        get => longPressEvent;
        set => longPressEvent = value;
    }
    
    public override void OnPointerDown(PointerEventData eventData)
    {
        base.OnPointerDown(eventData);
        if (longPressEnabled)
        {
            hasInvokedLongPress = false;
            isPressing = true;
            lastPressTime = Time.unscaledTime;   
        }
    }

    public override void OnPointerUp(PointerEventData eventData)
    {
        base.OnPointerUp(eventData);
        isPressing = false;
        hasInvokedLongPress = false;
    }

    private void Update()
    {
        DealLongPress();
    }
    
    private void DealLongPress()
    {
        if(hasInvokedLongPress) return;
        if (isPressing)
        {
            if (Time.unscaledTime - lastPressTime >= minPressTime)
            {
                UISystemProfilerApi.AddMarker("Button.onLongPress", this);
                onLongPress?.Invoke();
                hasInvokedLongPress = true;
                Debug.LogError("执行长按事件");
            }
        }
    }

    #endregion
}

Add the new properties to the Inspector panel, the specific code is as follows:

using UnityEngine;

namespace UnityEditor.UI
{
    [CustomEditor(typeof(ButtonExtension), true)]
    [CanEditMultipleObjects]
    public class ButtonExInspector : SelectableEditor
    {
        private ButtonExtension buttonExtension;

        SerializedProperty onDoubleClickProperty;
        SerializedProperty onClickProperty;
        SerializedProperty onLongPressProperty;
        
        protected override void OnEnable()
        {
            base.OnEnable();
            onDoubleClickProperty = serializedObject.FindProperty("doubleClickEvent");
            onClickProperty = serializedObject.FindProperty("m_OnClick");
            onLongPressProperty = serializedObject.FindProperty("longPressEvent");
        }

        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();
            serializedObject.Update();
            buttonExtension = (ButtonExtension)target;
            EditorGUILayout.Space();

            buttonExtension.singleClickEnabled = EditorGUILayout.Toggle("启用单击", buttonExtension.singleClickEnabled);
            if (buttonExtension.singleClickEnabled)
            {
                buttonExtension.doubleClickEnabled = false;
                buttonExtension.longPressEnabled = false;
                EditorGUILayout.PropertyField(onClickProperty);  
            }
            
            buttonExtension.doubleClickEnabled = EditorGUILayout.Toggle("启用双击", buttonExtension.doubleClickEnabled);
            if (buttonExtension.doubleClickEnabled)
            {
                buttonExtension.doubleClickTime = EditorGUILayout.FloatField("双击间隔", buttonExtension.doubleClickTime);
                buttonExtension.singleClickEnabled = false;
                buttonExtension.longPressEnabled = false;
                EditorGUILayout.PropertyField(onDoubleClickProperty);
            }
            
            buttonExtension.longPressEnabled = EditorGUILayout.Toggle("启用长按", buttonExtension.longPressEnabled);
            if(buttonExtension.longPressEnabled)
            {
                buttonExtension.minPressTime = EditorGUILayout.FloatField("长按时间", buttonExtension.minPressTime);
                buttonExtension.singleClickEnabled = false;
                buttonExtension.doubleClickEnabled = false;
                EditorGUILayout.PropertyField(onLongPressProperty);
            }
            
            serializedObject.ApplyModifiedProperties();
            if(GUI.changed)
                EditorUtility.SetDirty(target);
        }
    }   
}


Guess you like

Origin blog.csdn.net/lel18570471704/article/details/134789342