Unity自定义Button

2023.02.13更新:

新增右键单击属行,也开放了拓展内容,使用者可以随意编辑。

删除部分无用代码,让代码更简洁。

代码还是在下方

2022.10.27更新:

该代码中包含以下几个事件:保持按下事件,与其他事件共存

双击事件会先触发单击,这个问题已经解决,抱歉拖了这么久才完善.

并且新按钮命名为:ButtonPro

/* 
 * ================================================
 * Describe:      This script is used to custom UGUI`s button. 
 * Author:        Xiaohei.Wang(Wenhao)
 * CreationTime:  2022-10-26 16:43:48
 * ModifyAuthor:  Xiaohei.Wang(Wenhao)
 * ModifyTime:    2023-02-13 15:59:18
 * ScriptVersion: 0.1
 * ===============================================
*/

using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
using UnityEngine.UI;
using static UnityEngine.EventSystems.PointerEventData;

namespace EasyFramework.UI
{
    [AddComponentMenu("UI/Button Pro", 101)]
    [RequireComponent(typeof(Image))]
    [RequireComponent(typeof(CanvasRenderer))]
    public class ButtonPro : Selectable
    {
        protected ButtonPro() { }

        [Serializable]
        public class ButtonClickedEvent : UnityEvent { }

        [FormerlySerializedAs("onClick0")]
        [SerializeField]
        private ButtonClickedEvent m_OnClick0 = new ButtonClickedEvent();

        [FormerlySerializedAs("onClick1")]
        [SerializeField]
        private ButtonClickedEvent m_OnClick1 = new ButtonClickedEvent();

        [FormerlySerializedAs("onLongPress0")]
        [SerializeField]
        private ButtonClickedEvent m_onLongPress0 = new ButtonClickedEvent();

        [FormerlySerializedAs("onDoubleClick0")]
        [SerializeField]
        private ButtonClickedEvent m_onDoubleClick0 = new ButtonClickedEvent();

        [FormerlySerializedAs("onKeepPress0")]
        [SerializeField]
        private ButtonClickedEvent m_onKeepPress0 = new ButtonClickedEvent();

        public ButtonClickedEvent onClick0
        {
            get { return m_OnClick0; }
        }
        public ButtonClickedEvent onClick1
        {
            get { return m_OnClick1; }
        }
        public ButtonClickedEvent onDoubleClick0
        {
            get { return m_onDoubleClick0; }
        }
        public ButtonClickedEvent onLongPress0
        {
            get { return m_onLongPress0; }
        }
        public ButtonClickedEvent onKeepPress0
        {
            get { return m_onKeepPress0; }
        }

        private float m_longPressIntervalTime = 600.0f;
        private float m_doubleClcikIntervalTime = 170.0f;

        private float m_clickCount = 0;
        private bool m_onHoldDown = false;
        private bool m_isKeepPress = false;
        private bool m_onEventTrigger = false;
        private double m_clickIntervalTime = 0;
        private DateTime m_clickStartTime;

        private void OnAnyEventTrigger()
        {
            m_clickCount = 0;
            m_onEventTrigger = true;
            m_clickStartTime = default;
        }

        private void Press()
        {
            if (!IsActive() || !IsInteractable())
                return;
            Debug.LogWarning("sssssssssssssssss");
            UISystemProfilerApi.AddMarker("Button.onClick", this);
            m_OnClick0.Invoke();
        }

        private void Update()
        {
            if (!interactable) return;
            m_clickIntervalTime = (DateTime.Now - m_clickStartTime).TotalMilliseconds;

            if (!m_onHoldDown && 0 != m_clickCount)
            {
                if (m_clickIntervalTime >= m_doubleClcikIntervalTime && m_clickIntervalTime < m_longPressIntervalTime)
                {
                    if (m_clickCount == 2)
                        m_onDoubleClick0?.Invoke();
                    else
                        onClick0?.Invoke();
                    OnAnyEventTrigger();
                }
            }

            if (m_onHoldDown && !m_onEventTrigger)
            {
                if (m_clickIntervalTime >= m_longPressIntervalTime)
                {
                    m_onHoldDown = false;
                    m_onLongPress0?.Invoke();
                    OnAnyEventTrigger();
                }
            }

            if (m_isKeepPress) onKeepPress0?.Invoke();
        }

        public override void OnPointerDown(PointerEventData eventData)
        {
            if (eventData.button == InputButton.Left)
            {
                m_onHoldDown = true;
                m_onEventTrigger = false;
                m_clickStartTime = DateTime.Now;
            }
            m_isKeepPress = true;
            base.OnPointerDown(eventData);
        }

        public override void OnPointerUp(PointerEventData eventData)
        {
            if (eventData.button == InputButton.Right)
            {
                onClick1?.Invoke();
                OnAnyEventTrigger();
            }
            else if (eventData.button == InputButton.Left && !m_onEventTrigger)
            {
                m_clickCount++;
                if (m_clickCount % 3 == 0)
                {
                    onClick0?.Invoke();
                    OnAnyEventTrigger();
                    return;
                }
                else
                {
                    m_onHoldDown = false;
                    m_isKeepPress = false;
                }
            }
            m_isKeepPress = false;

            base.OnPointerUp(eventData);
        }

        public override void OnPointerExit(PointerEventData eventData)
        {
            if (eventData.button == InputButton.Left)
            {
                m_onHoldDown = false;
            }
            m_isKeepPress = false;

            base.OnPointerExit(eventData);
        }
    }
}

2022.01.15的内容:

该代码中包含以下几个事件:其中按着事件,与其他事件共存双击事件会先触发单击

  • onClick                         单击
  • onDoubleClick             双击
  • onLongPress               长按
  • onKeepPress               按着

 

 大家可以根据自己的需求来使用,也可以进行拓展,可能小黑的代码水平不高,但是希望能帮助到大家,如果你们拓展了告诉小黑一下,小黑会加到博客中来,并且标明是谁提供。

更新:

        2022.01.17:增加面板属性Interactable的作用。

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
using UnityEngine.UI;

namespace CustomTools
{
    /*
     * Introduction:Custom UGUI`s button
     * Creator:Xiaohei Wang
     */
    [RequireComponent(typeof(Image))]
    [RequireComponent(typeof(CanvasRenderer))]
    public class CustomButton : Selectable, IPointerClickHandler, ISubmitHandler
    {
        protected CustomButton() { }

        [Serializable]
        public class ButtonClickedEvent : UnityEvent { }

        [FormerlySerializedAs("onClick")]
        [SerializeField]
        private ButtonClickedEvent m_OnClick = new ButtonClickedEvent();

        [FormerlySerializedAs("onLongPress")]
        [SerializeField]
        private ButtonClickedEvent m_onLongPress = new ButtonClickedEvent();

        [FormerlySerializedAs("onDoubleClick")]
        [SerializeField]
        private ButtonClickedEvent m_onDoubleClick = new ButtonClickedEvent();

        [FormerlySerializedAs("onKeepPress")]
        [SerializeField]
        private ButtonClickedEvent m_onKeepPress = new ButtonClickedEvent();

        public ButtonClickedEvent onClick
        {
            get { return m_OnClick; }
        }
        public ButtonClickedEvent onDoubleClick
        {
            get { return m_onDoubleClick; }
        }
        public ButtonClickedEvent onLongPress
        {
            get { return m_onLongPress; }
        }
        public ButtonClickedEvent onKeepPress
        {
            get { return m_onKeepPress; }
        }

        private bool m_isPress = false;
        private bool m_longPress = false;
        private bool m_isKeepPress = false;
        private DateTime m_currentStartTime;


        private void Press()
        {
            if (!IsActive() || !IsInteractable())
                return;

            UISystemProfilerApi.AddMarker("Button.onClick", this);
            m_OnClick.Invoke();
        }

        private void Update()
        {
            if (!this.interactable) return;
            CheckForLongPress();

            if (m_isKeepPress) onKeepPress?.Invoke();
        }

        private void CheckForLongPress()
        {
            if (m_isPress && !m_longPress)
            {
                if ((DateTime.Now - m_currentStartTime).TotalMilliseconds >= 600)
                {
                    m_isPress = false;
                    m_longPress = true;
                    m_onLongPress?.Invoke();
                }
            }
        }

        public override void OnPointerDown(PointerEventData eventData)
        {
            m_isPress = true;
            m_longPress = false;
            m_isKeepPress = true;
            m_currentStartTime = DateTime.Now;

            base.OnPointerDown(eventData);
        }

        public override void OnPointerUp(PointerEventData eventData)
        {
            m_isPress = false;
            m_isKeepPress = false;

            base.OnPointerUp(eventData);
        }

        public override void OnPointerExit(PointerEventData eventData)
        {
            m_isPress = false;
            m_isKeepPress = false;

            base.OnPointerExit(eventData);
        }

        public virtual void OnPointerClick(PointerEventData eventData)
        {
            if (this.interactable && !m_longPress)
            {
                if (eventData.clickCount == 2)
                    m_onDoubleClick?.Invoke();
                else if (eventData.clickCount == 1)
                    onClick?.Invoke();
            }
        }

        public virtual void OnSubmit(BaseEventData eventData)
        {
            Press();

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

            DoStateTransition(SelectionState.Pressed, false);
            StartCoroutine(OnFinishSubmit());
        }

        private IEnumerator OnFinishSubmit()
        {
            var fadeTime = colors.fadeDuration;
            var elapsedTime = 0f;

            while (elapsedTime < fadeTime)
            {
                elapsedTime += Time.unscaledDeltaTime;
                yield return null;
            }

            DoStateTransition(currentSelectionState, false);
        }
    }
}

希望大家:点赞,留言,关注咯~    

😘😘😘😘

唠家常

  • 小黑的今日分享结束啦,小伙伴们你们get到了么,你们有没有更好的办法呢,可以评论区留言分享,也可以加小黑的QQ:841298494,大家一起进步

今日无推荐

### 回答1: Unity自带的菜单选项可以为开发人员提供快捷的功能,但是当我们需要一个更加专业化的菜单时,Unity的默认菜单选项可能无法满足需求。此时,自定义树形菜单就应运而生。 Unity自定义树形菜单是基于EditorGUILayout的GUI实现的。首先,我们需要扩展Editor类并使用MenuCommand属性,以及EditorGUI类,来为自定义菜单添加菜单项和功能选项。然后,我们可以使用GUILayout实现垂直排列的树形菜单,在每个菜单项的后面添加子菜单。 接下来,我们应该为自定义菜单添加相应的功能。在每个菜单项中,我们可以通过EditorGUILayout实现按钮、文本框、下拉菜单等等,为每个功能选项设计对应的功能。比如,我们可以在菜单项中添加新的对象、展开/折叠所有对象、删除特定的对象等功能。 最后,我们需要重写OnGUI方法,在其中调用自己的菜单绘制函数。这样,在编辑器中打开自定义窗口时,我们就可以看到新的树形菜单和功能选项了。另外,我们要记得在Menu选项中添加自定义的扩展菜单,这样才能在编辑器菜单中添加自己的菜单项。 总而言之,Unity自定义树形菜单功能可以让开发人员更加简便地实现自己的的菜单和功能选项。如果你想为Unity添加一些自定义的、专业化的菜单和功能选项,自定义树形菜单将是一个十分有效的解决方案。 ### 回答2: Unity是一款非常强大的游戏引擎,在其中可以进行大量的开发工作。其中,Unity提供了很多的功能和工具,其中就包括了自定义树形菜单。 在Unity中,树形菜单是一种非常方便的工具,可以让用户轻松地查看所有的功能和对象,并且方便进行管理。如果用户想要自定义树形菜单,可以按照以下的步骤进行操作: 1. 创建一个新的编辑器窗口,负责显示自定义树形菜单。 2. 在这个编辑器窗口中,可以使用GUILayout或者IMGUI等工具来自定义绘制。 3. 使用EditorApplication.hierarchyWindowChanged事件去监听当场景objectId的集合发生了改变时触发。 4. 使用UnityEditor.GUILayout.Popup方法样式,用户可以为每个节点添加下拉箭头。 5. 使用自定义GUILayout.Button方法样式,用户可以为每个节点添加列表中的按钮。 上述步骤是在Unity自定义树形菜单的基本过程,用户可以根据自己的需求进行更改和调整。自定义树形菜单可以大大提高工作效率,让开发者更加方便地管理和操作游戏中的场景、对象和功能。 ### 回答3: Unity是一款十分强大的游戏引擎,是许多游戏制作人员所钟爱的工具。Unity自带的菜单栏虽然已经很强大,但是我们还是有时候需要自定义树形菜单,来更好的实现游戏中的各种功能。这里我们将介绍如何使用Unity自定义树形菜单。 首先,打开Unity的编辑器并打开项目。然后在项目中新建一个C#脚本,并将其命名为“CustomMenu.cs”。我们将在这个脚本中编写我们的树形菜单。 接下来,我们需要为我们的树形菜单设置一个名称。在“CustomMenu.cs”中,使用“[MenuItem(“Custom/MyMenu”)]”,产生一个名为“MyMenu”的菜单。 接下来,我们可以在Unity的编辑器中创建一个新的文件夹,将其命名为“Custom”,这个文件夹将成为我们创建的菜单的父级。 接下来,在“CustomMenu.cs”中,我们可以使用“[MenuItem(“Custom/MyMenu/Do Something”)]”创建菜单的子项,并添加相应的函数来实现这个子项的功能。 最后,在Unity中运行我们的项目,并点击菜单栏“Custom”选项,我们就可以看到我们刚刚创建的树形菜单了。当我们点击“MyMenu”时,会显示“Do Something”子项。当我们点击“Do Something”时,它将调用相应的函数并执行相应的操作。 综上所述,Unity自定义树形菜单的实现方法是很简单的。我们只需要编写一个包含菜单名称和相应函数的脚本即可。可以根据需要创建任意多的子项,并为它们添加相应的功能。自定义菜单能够帮助我们更好地实现游戏中的各种功能,提高我们的工作效率,让我们更加专注于游戏的创作。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青衫磊落长歌行

觉得小黑这篇文章不赖,打赏哟~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值