一、简单介绍

UGUI,是Unity自带的 GUI 系统,有别于 NGUI;使用 UGUI 也能制作出比较酷炫的效果 。

本节简单介绍实现 UGUI 按钮的 长按功能,以及Double Click 的功能。

二、实现原理

1、继承原有的UGUI 的 Button,组件

2、在 Button 的上面实现长按和双击事件

三、注意事项

1、长按和双击事件实现和原有的单击事件方法类似(目前不能显示的面板中,估计还有注意什么,知道的朋友可以留言啊(可能是继承 Button 子类已经有 UnityEvent (还是奇怪)),后面脚本有完全重写的Button 中面板有 onClick, onLongPress, onDoubleClick 事件)

2、触发双击的时候,可能总是会触发一次单击事件,顺序是先触发单击事件,之后双击事件触发(尝试了一些方法暂时没有方法在取消双击前的单击,知道的朋友留言哈)

四、效果预览

五、实现步骤

1、打开Unity,新建空工程

2、在场景中,简单布局场景,方便测试

3、新建脚本 MuButton,继承 Button,代码实现长按和双击效果的逻辑,并添加一个测试脚本,测试 MyButton 效果

4、移除Button 上的Button组件,添加 MyButton

5、添加测试脚本 TestMyButton

6、运行场景,测试效果如上

六、关键代码

1、MyButton.cs

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
/// <summary>
/// 我的自定义Button,继承 Button
/// </summary>
public class MyButton : Button
   // 构造函数
    protected MyButton()
        my_onDoubleClick = new ButtonClickedEvent();
        my_onLongPress = new ButtonClickedEvent();
    // 长按
    public ButtonClickedEvent my_onLongPress;
    public ButtonClickedEvent OnLongPress
        get { return my_onLongPress; }
        set { my_onLongPress = value; }
    // 双击
    public ButtonClickedEvent my_onDoubleClick;
    public ButtonClickedEvent OnDoubleClick
        get { return my_onDoubleClick; }
        set { my_onDoubleClick = value; }
    // 长按需要的变量参数
    private bool my_isStartPress = false;
    private float my_curPointDownTime = 0f;
    private float my_longPressTime = 0.6f;
    private bool my_longPressTrigger = false;
    void Update()
        CheckIsLongPress();
    #region 长按
    /// <summary>
    /// 处理长按
    /// </summary>
    void CheckIsLongPress() {
        if (my_isStartPress && !my_longPressTrigger)
            if (Time.time > my_curPointDownTime + my_longPressTime)
                my_longPressTrigger = true;
                my_isStartPress = false;
                if (my_onLongPress != null)
                    my_onLongPress.Invoke();
    public override void OnPointerDown(PointerEventData eventData)
        // 按下刷新當前時間
        base.OnPointerDown(eventData);
        my_curPointDownTime = Time.time;
        my_isStartPress = true;
        my_longPressTrigger = false;
    public override void OnPointerUp(PointerEventData eventData)
        // 指針擡起,結束開始長按
        base.OnPointerUp(eventData);
        my_isStartPress = false;
    public override void OnPointerExit(PointerEventData eventData)
        // 指針移出,結束開始長按,計時長按標志
        base.OnPointerExit(eventData);
        my_isStartPress = false;
    #endregion
    #region 双击(单击)
    public override void OnPointerClick(PointerEventData eventData)
        //(避免已經點擊進入長按后,擡起的情況)
        if (!my_longPressTrigger)
            // 正常單擊 
            if (eventData.clickCount == 2 )
                if (my_onDoubleClick != null)
                    my_onDoubleClick.Invoke();
            }// 雙擊
            else if (eventData.clickCount == 1)
                onClick.Invoke();
    #endregion

2、TestMyButton.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestMyButton : MonoBehaviour
    public MyButton myButton;
    // Start is called before the first frame update
    void Start()
        myButton.onClick.AddListener(()=> {
            Debug.Log(" myButton.onClick");
        myButton.OnDoubleClick.AddListener(() => {
            Debug.Log(" myButton.OnDoubleClick");
        myButton.OnLongPress.AddListener(() => {
            Debug.Log(" myButton.OnLongPress");
    // Update is called once per frame
    void Update()

七、自己完全重写 Button (面板有 onClick, onLongPress, onDoubleClick 事件添加)

(注意:使用方法原有的Button一样)

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;
using UnityEngine.Serialization;
using UnityEngine;
namespace XANTools
    /// <summary>
    /// 自己重写的 Button 按钮
    /// 1、单击
    /// 2、双击
    /// 3、长按
    /// </summary>    
    public class MyButtonXAN : Selectable, IPointerClickHandler, ISubmitHandler
        [Serializable]
        /// <summary>
        /// Function definition for a button click event.
        /// </summary>
        public class ButtonClickedEvent : UnityEvent { }
        // Event delegates triggered on click.
        [FormerlySerializedAs("onClick")]
        [SerializeField]
        private ButtonClickedEvent m_OnClick = new ButtonClickedEvent();
        protected MyButtonXAN()
        public ButtonClickedEvent onClick
            get { return m_OnClick; }
            set { m_OnClick = value; }
        private void Press()
            if (!IsActive() || !IsInteractable())
                return;
            UISystemProfilerApi.AddMarker("Button.onClick", this);
            m_OnClick.Invoke();
        [Serializable]
        /// <summary>
        /// Function definition for a button click event.
        /// </summary>
        public class ButtonLongPressEvent : UnityEvent { }
        [FormerlySerializedAs("onLongPress")]
        [SerializeField]
        private ButtonLongPressEvent m_onLongPress = new ButtonLongPressEvent();
        public ButtonLongPressEvent onLongPress
            get { return m_onLongPress; }
            set { m_onLongPress = value; }
        [FormerlySerializedAs("OnDoubleClick")]
        public ButtonClickedEvent m_onDoubleClick = new ButtonClickedEvent();
        public ButtonClickedEvent OnDoubleClick
            get { return m_onDoubleClick; }
            set { m_onDoubleClick = value; }
        private bool my_isStartPress = false;
        private float my_curPointDownTime = 0f;
        private float my_longPressTime = 0.6f;
        private bool my_longPressTrigger = false;
        void Update()
            CheckIsLongPress();
        void CheckIsLongPress()
            if (my_isStartPress && !my_longPressTrigger)
                if (Time.time > my_curPointDownTime + my_longPressTime)
                    my_longPressTrigger = true;
                    my_isStartPress = false;
                    if (m_onLongPress != null)
                        m_onLongPress.Invoke();
        public virtual void OnPointerClick(PointerEventData eventData)
            //(避免已經點擊進入長按后,擡起的情況)
            if (!my_longPressTrigger)
                // 正常單擊 
                if (eventData.clickCount == 2)
                    if (m_onDoubleClick != null)
                        m_onDoubleClick.Invoke();
                }// 雙擊
                else if (eventData.clickCount == 1)
                    onClick.Invoke();
        public virtual void OnSubmit(BaseEventData eventData)
            Press();
            // if we get set disabled during the press
            // don't run the coroutine.
            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);
        public override void OnPointerDown(PointerEventData eventData)
            // 按下刷新當前時間
            base.OnPointerDown(eventData);
            my_curPointDownTime = Time.time;
            my_isStartPress = true;
            my_longPressTrigger = false;
        public override void OnPointerUp(PointerEventData eventData)
            // 指針擡起,結束開始長按
            base.OnPointerUp(eventData);
            my_isStartPress = false;
        public override void OnPointerExit(PointerEventData eventData)
            // 指針移出,結束開始長按,計時長按標志
            base.OnPointerExit(eventData);
            my_isStartPress = false;
                                    Unity UI案例(按钮双击按钮Unity中要实现自己得Button需要编写继承自UnityEngine的Button类,然后再重写按钮按下,抬起,和离开的方法(OnPointerDown,OnPointerUp,OnPointerExit),记录时间差就行了,具体实现看代码:
一:按钮实现:
public class LongClickButton : Button {
                                    以下内容是根据Unity 2020.1.01f版本进行编写的
UGUI源代码之Button按钮1、目的2、参考3、代码阅读4、准备修改UGUI源代码5、自定义实现按钮6、最终效果7、项目工程源代码
按钮应该是很常见也很实用的一个功能了吧,今天我们就来实现这个功能
本文参考Unity官方的UGUI源代码
Github地址:https://github.com/Unity-Technologies/uGUI
3、代码阅读
查看Button源代码(部分):
public 
public class View_ATKNormalPress : StateMachineBehaviour {
     // OnStateEnter is called when a transition starts a
                                    Unity实现按钮Button功能按,双击)。
今天在做游戏的时候突发奇想,为什么Unity只有单击捏?例如:以前的iPhone的Home键双击就是任务栏,单击就是回到主界面。那么在Unity应该也能实现吧(好像没什么关联。。。),毕竟现在很多游戏都存在双击功能。于是我去网络上查找并学习了下,把心得写在这,方便大家可以参考参考。
既然我们需要手动写一个按钮,那么就需要去监听GameObject的点击事件。这里我设置了几个Public变量,并且实现了几个鼠标事件的接口,具体的代码如下:
                                    还在用Update计时器实现各种流程控制和状态判断吗?今次介绍一下使用UnityEvents实现uGUI按状态检测。效果案例是我们常见的微信按弹出菜单。
使用事件,首先需要添加引用。
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;在继承后面添加接口,用来获取UI状态。
                                    public class ClickEventListener : MonoBehaviour, IPointerClickHandler, IPointerDownHandler, IPointerUpHandler
        public static ClickEventListener Get(GameObject obj)
接下来便要实现双击功能,再次附上以前已写好的点击事件:using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSyste
                                    ​ 虽然 UGUI 的 RectTransform 已经非常方便的可以帮助我们快速布局,但 UGUI 中还提供了很多可以帮助我们对 UI 控件进行自动布局的组件,他们可以帮助我们自动的设置 UI 控件的位置和大小等。​ 如果想做一些类似按,双击,拖拽等功能是无法制作的,或者想让 Image 和 Text,RawImage 三大基础控件能够响应玩家输入也是无法制作的。​ 一般情况下布局元素的这些属性都是 0,但是特定的 UI 组件依附的对象布局属性会被改变,比如 Image 和 Text。