转:ButtonEx扩展按钮组件,添加右键点击支持

原文出自:https://www.cnblogs.com/SouthBegonia/p/16093683.html

添加了右键支持,但是只有单击,注意不要跟项目中其他鼠标右键的功能冲突,鼠标中键也需要的话自己改造一下就行了

using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
#if UNITY_EDITOR
using UnityEditor;
#endif

/*
 * ButtonEx扩展按钮组件
 *
 * 【功能】
 *     - 多种按钮交互事件
 *     - Button无损转ButtonEx(Button右上角三个点设置里调用)
 */

/// <summary>
/// 扩展按钮组件
/// </summary>
[AddComponentMenu("UI/ButtonEx")]
public class ButtonEx : Button
{
    /// <summary>
    /// 按钮交互事件枚举
    /// </summary>
    [System.Flags]
    public enum EventType
    {
        Click = 1 << 0,
        LongClick = 1 << 1,
        Down = 1 << 2,
        Up = 1 << 3,
        Enter = 1 << 4,
        Exit = 1 << 5,
        DoubleClick = 1 << 6,
    }

    [SerializeField] private EventType m_EventType = EventType.Click;
    /// <summary>
    /// 长按判定时间
    /// </summary>
    public float onLongWaitTime = 0.2f;

    /// <summary>
    /// 是否重复抛出长按事件(false:长按onLongWaitTime后只触发一次onLongClick  true:从onDown起,每onLongWaitTime触发一次onLongClick)
    /// </summary>
    public bool onLongContinue = false;

    /// <summary>
    /// 双击判定时间(两次OnDown的间隔时间小于此值即判定为一次双击,但完全不影响onClick的触发)
    /// </summary>
    public float onDoubleClickTime = 0.5f;


    /*[SerializeField]
    private ButtonClickedEvent m_OnClick = new ButtonClickedEvent(); //点击事件*/

    [SerializeField] private ButtonClickedEvent m_OnEnterLongClick = new ButtonClickedEvent(); //长按事件(触发一次)
    
    [SerializeField] private ButtonClickedEvent m_OnLongClick = new ButtonClickedEvent(); //长按事件(触发一次)

    [SerializeField] private ButtonClickedEvent m_OnDown = new ButtonClickedEvent(); //按下事件

    [SerializeField] private ButtonClickedEvent m_OnUp = new ButtonClickedEvent(); //抬起事件

    [SerializeField] private ButtonClickedEvent m_OnEnter = new ButtonClickedEvent(); //进入事件

    [SerializeField] private ButtonClickedEvent m_OnExit = new ButtonClickedEvent(); //移出事件

    [SerializeField] private ButtonClickedEvent m_onDoubleClick = new ButtonClickedEvent(); //双击事件
    
    [SerializeField] private ButtonClickedEvent m_onRightClick = new ButtonClickedEvent(); //右键点击事件
    
    [SerializeField] private ButtonClickedEvent m_OnClickEx = new ButtonClickedEvent(); //左键点击事件

    private Coroutine log;

    private bool isPointerDown = false;
    private bool isPointerInside = false;

    private bool isEnterButton;
    #region 对外属性

    /// <summary>
    /// 是否被按下
    /// </summary>
    public bool isDown
    {
        get { return isPointerDown; }
    }

    /// <summary>
    /// 是否进入
    /// </summary>
    public bool isEnter
    {
        get { return isPointerInside; }
    }

    /// <summary>
    /// 点击事件
    /// </summary>
    public ButtonClickedEvent onClickEx
    {
        get { return this.m_OnClickEx; }
        set { this.m_OnClickEx = value; }
    }


    public ButtonClickedEvent onLongEnterClick
    {
        get
        {
            return this.m_OnEnterLongClick;
        }
        set
        {
            this.m_OnEnterLongClick = value;
        }
    }
    
    /// <summary>
    /// 长按事件
    /// </summary>
    public ButtonClickedEvent onLongClick
    {
        get { return m_OnLongClick; }
        set { m_OnLongClick = value; }
    }

    /// <summary>
    /// 双击事件
    /// </summary>
    public ButtonClickedEvent onDoubleClick
    {
        get { return m_onDoubleClick; }
        set { m_onDoubleClick = value; }
    }
    
    /// <summary>
    /// 右键点击事件
    /// </summary>
    public ButtonClickedEvent onRightClick
    {
        get { return m_onRightClick; }
        set { m_onRightClick = value; }
    }

    /// <summary>
    /// 按下事件
    /// </summary>
    public ButtonClickedEvent onDown
    {
        get { return m_OnDown; }
        set { m_OnDown = value; }
    }

    /// <summary>
    /// 松开事件
    /// </summary>
    public ButtonClickedEvent onUp
    {
        get { return m_OnUp; }
        set { m_OnUp = value; }
    }

    /// <summary>
    /// 进入事件
    /// </summary>
    public ButtonClickedEvent onEnter
    {
        get { return m_OnEnter; }
        set { m_OnEnter = value; }
    }

    /// <summary>
    /// 离开事件
    /// </summary>
    public ButtonClickedEvent onExit
    {
        get { return m_OnExit; }
        set { m_OnExit = value; }
    }

    #endregion


    private float lastClickTime;
    
    protected override void Awake()
    {
        base.Awake();
        this.onClickEx.AddListener(() => {DoStateTransition(SelectionState.Highlighted, false); });
    }

    private void Down()
    {
        if (!IsActive() || !IsInteractable())
            return;
        m_OnDown.Invoke();
        if (lastClickTime != 0 && Time.time - lastClickTime <= onDoubleClickTime)
        {
            DoubleClick();
        }

        lastClickTime = Time.time;
        log = StartCoroutine(grow());
    }

    private void Up()
    {
        if (!IsActive() || !IsInteractable() || !isDown)
            return;
        
        m_OnUp.Invoke();
        if (log != null)
        {
            StopCoroutine(log);
            log = null;
        }
    }

    private void Enter()
    {
        if (!IsActive())
            return;
        m_OnEnter.Invoke();
        isEnterButton = true;
        StartCoroutine(LongEnterButton());
    }

    private float enterTime = 0f;
    private IEnumerator LongEnterButton()
    {
        enterTime = Time.time;
        while (isEnterButton)
        {
            if (Time.time - enterTime > onLongWaitTime)
            {
                m_OnEnterLongClick?.Invoke();
                isEnterButton = false;
                if (onLongContinue)
                    enterTime = Time.time;
                else
                    break;
            }
            else
                yield return null;
        }
    }
    private void Exit()
    {
        if (!IsActive() || !isEnter)
            return;
        m_OnExit.Invoke();
        this.isEnterButton = false;
    }

    private void LongClick()
    {
        if (!IsActive() || !isDown)
            return;
        m_OnLongClick.Invoke();
    }
    
    private void LongEnterClick()
    {
        if (!IsActive() || !this.isEnterButton)
            return;
        m_OnLongClick.Invoke();
    }

    private void DoubleClick()
    {
        if (!IsActive() || !isDown)
            return;
        m_onDoubleClick.Invoke();
    }

    private float downTime = 0f;
    private IEnumerator grow()
    {
        downTime = Time.time;
        while (isDown)
        {
            if (Time.time - downTime > onLongWaitTime)
            {
                LongClick();
                if (onLongContinue)
                    downTime = Time.time;
                else
                    break;
            }
            else
                yield return null;
        }
    }

    protected override void OnDisable()
    {
        isPointerDown = false;
        isPointerInside = false;
        base.OnDisable();
    }
    
    public override void OnPointerClick(PointerEventData eventData)
    {
        //中键点击直接返回
        if (eventData.button == PointerEventData.InputButton.Middle)
        {
            return;
        }

        if (!IsActive() || !IsInteractable())
        {
            return;
        }

        UISystemProfilerApi.AddMarker("Button.onClick", this);
        if (eventData.button == PointerEventData.InputButton.Left)
        {
            this.onClickEx.Invoke();
        }
        else
        {
            this.m_onRightClick.Invoke();
        }
    }
    
    public override void OnPointerDown(PointerEventData eventData)
    {
        if (eventData.button != PointerEventData.InputButton.Left)
            return;
        
        isPointerDown = true;
        Down();
        base.OnPointerDown(eventData);
    }

    public override void OnPointerUp(PointerEventData eventData)
    {
        if (eventData.button != PointerEventData.InputButton.Left)
            return;
        Up();
        isPointerDown = false;
        base.OnPointerUp(eventData);
    }

    public override void OnPointerEnter(PointerEventData eventData)
    {
        base.OnPointerEnter(eventData);
        isPointerInside = true;
        Enter();
        if (interactable)
        {
            DoStateTransition(SelectionState.Highlighted, true);
        }
    }

    public override void OnPointerExit(PointerEventData eventData)
    {
        Exit();
        isPointerInside = false;
        base.OnPointerExit(eventData);
        if (interactable)
        {
            DoStateTransition(SelectionState.Normal, true);
        }
    }

    #region Button->ButtonEx转换相关

#if UNITY_EDITOR

    [MenuItem("CONTEXT/Button/Convert To ButtonEx", true)]
    static bool _ConvertToButtonEx(MenuCommand command)
    {
        return CanConvertTo<ButtonEx>(command.context);
    }

    [MenuItem("CONTEXT/Button/Convert To ButtonEx", false)]
    static void ConvertToButtonEx(MenuCommand command)
    {
        ConvertTo<ButtonEx>(command.context);
    }

    [MenuItem("CONTEXT/Button/Convert To Button", true)]
    static bool _ConvertToButton(MenuCommand command)
    {
        return CanConvertTo<Button>(command.context);
    }

    [MenuItem("CONTEXT/Button/Convert To Button", false)]
    static void ConvertToButton(MenuCommand command)
    {
        ConvertTo<Button>(command.context);
    }

    protected static bool CanConvertTo<T>(Object context)
        where T : MonoBehaviour
    {
        return context && context.GetType() != typeof(T);
    }

    protected static void ConvertTo<T>(Object context) where T : MonoBehaviour
    {
        var target = context as MonoBehaviour;
        var so = new SerializedObject(target);
        so.Update();

        bool oldEnable = target.enabled;
        target.enabled = false;

        // Find MonoScript of the specified component.
        foreach (var script in Resources.FindObjectsOfTypeAll<MonoScript>())
        {
            if (script.GetClass() != typeof(T))
                continue;

            // Set 'm_Script' to convert.
            so.FindProperty("m_Script").objectReferenceValue = script;
            so.ApplyModifiedProperties();
            break;
        }

        (so.targetObject as MonoBehaviour).enabled = oldEnable;
    }
#endif

    #endregion

}
using System;
using UnityEngine;
using UnityEditor;
using UnityEditor.UI;
using System.Collections.Generic;
using EventType = ButtonEx.EventType;

[CustomEditor(typeof (ButtonEx), true)]
public class ButtonExEditor: SelectableEditor
{
    /// <summary>
    /// 按钮交互事件绘制方法的字典
    /// </summary>
    Dictionary<EventType, Action> callbackDrawersDic;

    private SerializedProperty spType;

    /// <summary>
    /// 按钮交互事件属性的字典
    /// </summary>
    Dictionary<EventType, SerializedProperty> eventPropertiesDic;

    private SerializedProperty sponLongWaitTime;

    private SerializedProperty sponLongContinue;

    private SerializedProperty sponDoubleClickTime;

    protected override void OnEnable()
    {
        base.OnEnable();

        //初始化各属性
        InitProperties();
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        serializedObject.Update();

        GUILayout.Space(15);

        // 绘制按钮相关参数
        sponLongWaitTime.floatValue = EditorGUILayout.FloatField("长按判定时间", sponLongWaitTime.floatValue);
        sponLongContinue.boolValue = EditorGUILayout.Toggle("长按期间是否持续触发", sponLongContinue.boolValue);
        sponDoubleClickTime.floatValue = EditorGUILayout.FloatField("双击间隔判定时间", sponDoubleClickTime.floatValue);

        // 绘制按钮交互事件栏
        GUILayout.Space(10);
        int oldType = spType.intValue;
        spType.intValue = (int)((EventType)EditorGUILayout.EnumFlagsField(new GUIContent("按钮交互事件"), (EventType)spType.intValue));
        foreach (EventType e in Enum.GetValues(typeof (EventType)))
        {
            if (0 < (spType.intValue & (int)e))
                callbackDrawersDic[e]();
            else if (0 < (oldType & (int)e))
                eventPropertiesDic[e].FindPropertyRelative("m_PersistentCalls").FindPropertyRelative("m_Calls").ClearArray();
        }

        serializedObject.ApplyModifiedProperties();
    }

    private void InitProperties()
    {
        eventPropertiesDic = new Dictionary<EventType, SerializedProperty>()
        {
            { EventType.Click, serializedObject.FindProperty("m_OnClickEx") },
            { EventType.LongClick, serializedObject.FindProperty("m_OnLongClick") },
            { EventType.Down, serializedObject.FindProperty("m_OnDown") },
            { EventType.Up, serializedObject.FindProperty("m_OnUp") },
            { EventType.Enter, serializedObject.FindProperty("m_OnEnter") },
            { EventType.Exit, serializedObject.FindProperty("m_OnExit") },
            { EventType.DoubleClick, serializedObject.FindProperty("m_onDoubleClick") },
        };

        callbackDrawersDic = new Dictionary<EventType, Action>();
        foreach (EventType eventType in Enum.GetValues(typeof (EventType)))
        {
            callbackDrawersDic.Add(eventType, () =>
            {
                EditorGUILayout.LabelField(eventType.ToString(), EditorStyles.boldLabel);
                EditorGUILayout.PropertyField(eventPropertiesDic[eventType]);

                //可以根据EventType再特殊定制其他属性的显示
            });
        }

        spType = serializedObject.FindProperty("m_EventType");
        sponLongWaitTime = serializedObject.FindProperty("onLongWaitTime");
        sponLongContinue = serializedObject.FindProperty("onLongContinue");
        sponDoubleClickTime = serializedObject.FindProperty("onDoubleClickTime");
    }
}

另外,如果需要图片切换的按钮的话,可以参考这个链接,上面已经整合:Unity学习笔记 关于Ugui Button按钮的选择状态详解以及可替代方案

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值