UGUI中Button添加事件大总结(有参,无参,动态)

发表于2018-06-13
评论0 4.3k浏览
总结了从网上看到的大部分Button添加事件的方法,总结了有9种方法,中间原理可能有重复的,最后是一些注意事项。

一、Inspector面板拖拽添加无参函数

1.Hierarchy窗口建立一个空物体

2.创建Button和一个空物体GameObject

3.创建脚本DTPractice,挂在GameObject上
DTPractice.cs
public class DTPractice : MonoBehaviour{  
  public void OnClickBtn1()  
    {  
        Debug.Log("Click1");  
    }  
}

Button上的设置:

运行结果:

二、Inspector面板拖拽添加有参函数

和第一中方法一样,只是在公有函数中添加参数
DTPractice.cs
public class DTPractice : MonoBehaviour{  
  public void OnClickBtn2(int i)  
    {  
        Debug.Log("Click2"+"参数"+i);  
    }  
} 

再Button的Inspector界面设置:

输入对应参数,运行结果:

上面两种方法都必须是公有的

三、使用AddListener添加无参的回调函数

1.DTPractice.cs脚本绑定在GameObject空物体上

2.使用拖拽将Button赋值到DTPractice脚本中

DTPractice.cs
public class DTPractice : MonoBehaviour{  
    public GameObject btn3;  
    private void Start()  
    {  
        btn3.GetComponent<Button>().onClick.AddListener(OnClickBtn3);  
    }  
    void OnClickBtn3()  
    {  
        Debug.Log("Click3");  
    }  
} 

或者直接输出
public class DTPractice : MonoBehaviour{  
    public GameObject btn3;  
    private void Start()  
    {  
        btn3.GetComponent<Button>().onClick.AddListener(  
            delegate()  
            {  
                Debug.Log("Click3Start");  
            }  
            );  
    }  
} 

输出结果:

相同原理的方法:本质就是获得Button组件

(1)DTPractice.cs脚本绑定在Button上
DTPractice.cs
public class DTPractice : MonoBehaviour{  
    private Button btn6;  
    private void Start()  
    {  
        btn6 = GetComponent<Button>();  
        btn6.onClick.AddListener(  
            delegate ()  
            {  
                Test t = GameObject.FindObjectOfType<Test>();  
                t.OnClickBtn6();  
            }  
            );  
    }  
} 

另一个脚本 Test.cs,绑定再GameObject空物体上
public class Test : MonoBehaviour {  
    public void OnClickBtn6()  
    {  
        Debug.Log("Click6");  
    } 

运行结果:

(2)或者通过名字查找获得Button组件进行监听
DTPractice.cs绑定在GameObject空物体上
public class DTPractice : MonoBehaviour{  
    private Button btn6;  
    private void Start()  
    {  
        btn6 = GameObject.Find("Button").GetComponent<Button>();  
        btn6.onClick.AddListener(  
            delegate ()  
            {  
                Test t = GameObject.FindObjectOfType<Test>();  
                t.OnClickBtn6();  
            }  
            );  
    }  
}  

四、使用AddListener添加有参数的回调函数

拖拽方式和方法三相同
DTPractice.cs
public class DTPractice : MonoBehaviour{  
    public GameObject btn3;  
    private void Start()  
    {  
        btn3.GetComponent<Button>().onClick.AddListener(  
            delegate()  
                {  
                    OnClickBtn3(3);  
                }  
            );  
    }  
    void OnClickBtn3(int i)  
    {  
        Debug.Log("Click3"+"num"+i);  
    }  
}  

运行结果:

五、自定义一个类继承自EventTrigger,并重写其中部分所需要的方法(可以延伸到UGUI中的各种事件)

先看下NGUI中的EventTriggerListener脚本
using UnityEngine;    
using UnityEngine.EventSystems;    
public class EventTriggerListener : EventTrigger    
{    
    public delegate void VoidDelegate(GameObject go);    
    public VoidDelegate onClick;    
    public VoidDelegate onDown;    
    public VoidDelegate onEnter;    
    public VoidDelegate onExit;    
    public VoidDelegate onUp;    
    public VoidDelegate onSelect;    
    public VoidDelegate onUpdateSelect;    
    public VoidDelegate onDrag;    
    public VoidDelegate onDrop;    
    public VoidDelegate onDeselect;    
    public VoidDelegate onScroll;    
    public VoidDelegate onMove;    
    public VoidDelegate onInitializePotentialDrag;    
    public VoidDelegate onBeginDrag;    
    public VoidDelegate onEndDrag;    
    public VoidDelegate onSubmit;    
    public VoidDelegate onCancel;    
    public override void OnPointerClick(PointerEventData eventData)    
    {    
        if (onClick != null) onClick(gameObject);    
    }    
    public override void OnPointerDown(PointerEventData eventData)    
    {    
        if (onDown != null) onDown(gameObject);    
    }    
    public override void OnPointerEnter(PointerEventData eventData)    
    {    
        if (onEnter != null) onEnter(gameObject);    
    }    
    public override void OnPointerExit(PointerEventData eventData)    
    {    
        if (onExit != null) onExit(gameObject);    
    }    
    public override void OnPointerUp(PointerEventData eventData)    
    {    
        if (onUp != null) onUp(gameObject);    
    }    
    public override void OnSelect(BaseEventData eventData)    
    {    
        if (onSelect != null) onSelect(gameObject);    
    }    
    public override void OnUpdateSelected(BaseEventData eventData)    
    {    
        if (onUpdateSelect != null) onUpdateSelect(gameObject);    
    }    
    public override void OnDrag(PointerEventData eventData)    
    {    
        if (onDrag != null) onDrag(gameObject);    
    }    
    public override void OnDrop(PointerEventData eventData)    
    {    
        if (onDrop != null) onDrop(gameObject);    
    }    
    public override void OnDeselect(BaseEventData eventData)    
    {    
        if (onDeselect != null) onDeselect(gameObject);    
    }    
    public override void OnScroll(PointerEventData eventData)    
    {    
        if (onScroll != null) onScroll(gameObject);    
    }    
    public override void OnMove(AxisEventData eventData)    
    {    
        if (onMove != null) onMove(gameObject);    
    }    
    public override void OnInitializePotentialDrag(PointerEventData eventData)    
    {    
        if (onInitializePotentialDrag != null) onInitializePotentialDrag(gameObject);    
    }    
    public override void OnBeginDrag(PointerEventData eventData)    
    {    
        if (onBeginDrag != null) onBeginDrag(gameObject);    
    }    
    public override void OnEndDrag(PointerEventData eventData)    
    {    
        if (onEndDrag != null) onEndDrag(gameObject);    
    }    
    public override void OnSubmit(BaseEventData eventData)    
    {    
        if (onSubmit != null) onSubmit(gameObject);    
    }    
    public override void OnCancel(BaseEventData eventData)    
    {    
        if (onCancel != null) onCancel(gameObject);    
    }    
    /// <summary>    
    /// 获取或添加一个事件侦听器到指定的游戏对象。用法和NGUI一样    
    /// </summary>    
    public static EventTriggerListener Get(GameObject go)    
    {    
        EventTriggerListener listener = go.GetComponent<EventTriggerListener>();    
        if (listener == null) listener = go.AddComponent<EventTriggerListener>();    
        return listener;    
    } 

NGUI底层就是封装了这个方法,所以在按钮动态添加事件的时候调用的就是上面脚本中的方法
同理写一个类似上面的脚本,用于UGUI
UGUI所提供的EventTrigger类如下:

涉及到各种操作函数,继承重写的时候只需要些能用到的函数,此处重写OnPointClick函数即可;
创建EventTriggerListener.cs脚本,继承字EventTrigger,该脚本不需要挂在场景中物体上也挂不了
public class EventTriggerListener : EventTrigger{  
    public delegate void ClickListener();  
    public ClickListener onClick;  
    /// <summary>  
    /// 从某个物体上获得EventTriggerListener脚本,没有的话添加该脚本  
    /// </summary>  
    /// <param name="trans"></param>//可以将参数换成GameObject类型,就和NGUI中动态添加回调函数的方法一样了  
    /// <returns></returns>  
    public static EventTriggerListener Get(Transform trans)    {  
        EventTriggerListener listener = trans.GetComponent<EventTriggerListener>();  
        if (listener==null)  
        {  
            listener = trans.gameObject.AddComponent<EventTriggerListener>();  
        }  
        return listener;  
    }  
    /// <summary>  
    /// 重写EventTrigger中该函数  
    /// </summary>  
    /// <param name="eventData"></param>  
    public override void OnPointerClick(PointerEventData eventData)  
    {  
        if (onClick != null)  
            onClick();//调用委托  
    }  
}

DTPractice.cs脚本进行测试,绑定在GameObject空物体上,btn5通过拖拽进行赋值
public class DTPractice : MonoBehaviour{  
    public GameObject btn5;  
    private void Start()  
    {  
        EventTriggerListener.Get(btn5.transform).onClick += OnClickBtn5;  
    }  
    void OnClickBtn5()  
    {  
        Debug.Log("Click5");  
    }  
}  

运行结果:

此方法的好处在于,可以实现UGUI提供的OnClick事件之外的事件如:OnPointDown(按下事件),OnPointExit(抬起事件)等,根据自己需求获取

六、通过EventTrigger实现按钮的点击事件,方法5是通过重写EventTrigger中的函数来进行,方法6直接使用EventTrigger来进行操作

DTPractice.cs脚本,绑定在Button按钮上,运行即可
using System.Collections;  
using System.Collections.Generic;  
using UnityEngine;  
using DG.Tweening;  
using UnityEngine.UI;  
using UnityEngine.EventSystems;  
[RequireComponent(typeof(EventTrigger))]  
public class DTPractice : MonoBehaviour{  
    private void Start()  
    {  
        Button btn6 = this.GetComponent<Button>();  
        EventTrigger trigger = btn6.gameObject.GetComponent<EventTrigger>();  
        EventTrigger.Entry entry1 = new EventTrigger.Entry();  
        EventTrigger.Entry entry2 = new EventTrigger.Entry();  
        EventTrigger.Entry entry3 = new EventTrigger.Entry();  
        entry1.eventID = EventTriggerType.PointerClick;//鼠标点击事件  
        entry2.eventID = EventTriggerType.PointerEnter;//鼠标进入事件  
        entry3.eventID = EventTriggerType.PointerExit;//鼠标滑出事件  
        entry1.callback = new EventTrigger.TriggerEvent();  
        entry1.callback.AddListener(M);  
        trigger.triggers.Add(entry1);//所有在此EventTrigger中注册的函数。存再triggers  
        entry2.callback = new EventTrigger.TriggerEvent();  
        entry2.callback.AddListener(N);  
        trigger.triggers.Add(entry2);  
        entry3.callback = new EventTrigger.TriggerEvent();  
        entry3.callback.AddListener(F);  
        trigger.triggers.Add(entry3);  
    }  
    void M(BaseEventData data)  
    {  
        Debug.Log("鼠标点击");  
    }  
    void N(BaseEventData data)  
    {  
        Debug.Log("鼠标进入");  
    }  
    void F(BaseEventData data)  
    {  
        Debug.Log("鼠标滑出");  
    }  
}  

运行结果:

也可以和方法五一样协程不同的事件状态

七、EventTrigger再Inspector界面添加实现按钮点击事件

按钮Button上添加EventTrigger组件,点击AddNewEventType,添加EventTrigger中的函数,然后进行拖拽赋值
DTPractice.cs脚本绑定在GameObject空物体上
DTPractice.cs  
public class DTPractice : MonoBehaviour{  
    public void M()  
    {  
        Debug.Log("鼠标点击");  
    }  
    public void N()  
    {  
        Debug.Log("鼠标进入");  
    }  
    public void F()  
    {  
        Debug.Log("鼠标滑出");  
    }  
}  

Inspector界面添加:

运行结果:

八、继承基础接口实现Button回调事件添加

UGUI的EventTrigger中可以看到是继承了很多的基础接口,做了一个封装,我们可以直接继承这些基础接口来实现功能
DTPractice.cs 脚本绑定在Button上
DTPractice.cs  
public class DTPractice : MonoBehaviour,IPointerClickHandler{  
   public void OnPointerClick(PointerEventData data)  
    {  
        Debug.Log("Click8");  
    }  
}

运行结果:

九、方法八的扩展,一个按钮的时候这么写可以,当界面中有多个按钮的时候使用一个观察者模式进行处理

写一个观察者类脚本UIEventListener.cs  实现所有基础接口,多个按钮来注册这个观察类脚本中的事件,就不用每个按钮都需要继承基础接口类,简化操作
UIEventListener.cs
public class UIEventListener : MonoBehaviour ,IPointerClickHandler,IPointerEnterHandler,IPointerExitHandler{  
    public delegate void UIEventProxy(GameObject obj);//一个委托对应多个事件  
    public event UIEventProxy OnClick;  
    public event UIEventProxy OnMouseEnter;  
    public event UIEventProxy OnMouseExit;  
    public void OnPointerClick(PointerEventData data)  
    {  
        if (OnClick != null)  
            OnClick(this.gameObject);  
    }  
    public void OnPointerEnter(PointerEventData data)  
    {  
        if (OnMouseEnter != null)  
            OnMouseEnter(this.gameObject);  
    }  
    public void OnPointerExit(PointerEventData data)  
    {  
        if (OnMouseExit != null)  
            OnMouseExit(this.gameObject);  
    }  
}  

Test.cs脚本绑定在Button上,注册UIEventListener脚本中的事件
public class Test : MonoBehaviour {  
    private void Start()  
    {  
        Button btn = this.GetComponent<Button>();  
        UIEventListener listener = btn.gameObject.AddComponent<UIEventListener>();  
        listener.OnClick += delegate (GameObject obj) { Debug.Log(obj.name + "OnClick"); };  
        listener.OnMouseEnter += delegate (GameObject obj) { Debug.Log(obj.name + "OnMouseEnter"); };  
        listener.OnMouseExit += delegate (GameObject obj) { Debug.Log(obj.name + "OnMouseExit"); };  
    }  
} 

运行结果:

十、注意事项:

1.AddListener每次调用的时候都会添加一个监听,不能放在Update中

2.如果脚本是DontDestroyOnLoad,记得再AddListener之前加上RemoveAllListener

3.如果不想移除按钮所有事件,可以使用button.OnClick.RemoveListener(btnAction)来移除指定事件,其中参数是UnityAction类型的

4.使用EventTrigger中的AddEventType添加事件,监听分解动作

各种Event触发的机理和时机:
(1)PointerEnter:指针(鼠标、手指等)进入目标(Button、Panel等)范围的瞬间;

(2)PointerExit:指针离开目标范围的瞬间;

(3)PointerDown:指针在目标范围内时:按下的瞬间;

(4)PointerUp:指针在目标范围内时:指针抬起的瞬间:即使指针抬起的瞬间不在目标范围内,也会触发;

(5)PointerClick:指针对目标完成一次点击的瞬间:如果指针抬起的瞬间不在目标范围内,便不会触发;在PointerUp之后执行;

(6)Drag:指针按住并移动时:如果按下不移动则不触发;即使拖动时指针不在目标范围内也会触发;

(7)Drop:(理解为有其他东西被扔到监听对象身上时触发)在指针抬起的瞬间:如果被拖拽目标A此时在另一目标B的范围内,并且目标B有对Drop的监听(目标A不需要,但需要能够Drag),则触发;否则不会触发;在PointerUp之后执行;

(8)Scroll:指针在目标范围内时:无论指针是否按下,滚动滚轮时触发;

(9)UpdateSelected:指针完成一次PointerClick后,每一帧都会执行一次对应事件(下文的Select只在最开始执行一次);

(10)Select:指针在目标范围内完成第一次点击后,目标变为"Select"状态;

(11)Deselect:指针在目标范围外完成第一次点击后,目标变为"Deselect"状态;

(12)Move:任意目标处于"Select“状态下时:通过『上』『下』『左』『右』键,或”W", "S", "A", "D" 等键改变了Axis轴的Value时触发(可用Input.GetAxis("AxisName")检测);

(13InitializePotentialDrag:指针在目标范围内按下时:初始化潜在的可拖动目标,在PointerDown之后,BeginDrag之前触发;

(14)BeginDrag:指针在目标范围内按下时:一旦移动便触发;即使拖动时指针不在目标范围内也会触发;

(15)EndDrag:指针在移动时抬起的瞬间:即使指针不在目标范围内也会触发;如果触发了Drop则在其之后触发;

(16)Submit:目标处于"Select“状态下时:点击”Submit"键(默认为"Enter"键)时触发;

(17)Cancel:目标处于"Select“状态下时:点击”Cancel"键(默认为"ESC"键)时触发;

都是在网上看到的方法,做个汇总而已。
来自:https://blog.csdn.net/weixin_37608784/article/details/80076509

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

0个评论