Implementation content:
Extend Unity's own Button component to achieve double-click and long-press effects based on the original click event;
Detailed code explanation:
- Click event handling:
- Control whether to enable click events through
singleClickEnabled
switch. - In
OnPointerClick
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.
- Control whether to enable click events through
- Double-click event handling:
- Control whether to enable double-click events through
doubleClickEnabled
switch. - In
OnPointerClick
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.
- Control whether to enable double-click events through
- Long press event handling:
- Control whether to enable long press events through
longPressEnabled
switch. - In
OnPointerDown
method, record the press time and mark the long press state. - In
OnPointerUp
method, reset the long press state. - Use
Update
method to detect long press regularly. If the long press time threshold is reached, the long press event callback is triggered.
- Control whether to enable long press events through
- 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.
- Use
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);
}
}
}