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

总结下从网上看到的大部分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脚本

1.using UnityEngine;  
2.using UnityEngine.EventSystems;  
3.  
4.public class EventTriggerListener : EventTrigger  
5.{  
6.    public delegate void VoidDelegate(GameObject go);  
7.    public VoidDelegate onClick;  
8.    public VoidDelegate onDown;  
9.    public VoidDelegate onEnter;  
10.    public VoidDelegate onExit;  
11.    public VoidDelegate onUp;  
12.    public VoidDelegate onSelect;  
13.    public VoidDelegate onUpdateSelect;  
14.    public VoidDelegate onDrag;  
15.    public VoidDelegate onDrop;  
16.    public VoidDelegate onDeselect;  
17.    public VoidDelegate onScroll;  
18.    public VoidDelegate onMove;  
19.    public VoidDelegate onInitializePotentialDrag;  
20.    public VoidDelegate onBeginDrag;  
21.    public VoidDelegate onEndDrag;  
22.    public VoidDelegate onSubmit;  
23.    public VoidDelegate onCancel;  
24.      
25.    public override void OnPointerClick(PointerEventData eventData)  
26.    {  
27.        if (onClick != null) onClick(gameObject);  
28.    }  
29.    public override void OnPointerDown(PointerEventData eventData)  
30.    {  
31.        if (onDown != null) onDown(gameObject);  
32.    }  
33.    public override void OnPointerEnter(PointerEventData eventData)  
34.    {  
35.        if (onEnter != null) onEnter(gameObject);  
36.    }  
37.    public override void OnPointerExit(PointerEventData eventData)  
38.    {  
39.        if (onExit != null) onExit(gameObject);  
40.    }  
41.    public override void OnPointerUp(PointerEventData eventData)  
42.    {  
43.        if (onUp != null) onUp(gameObject);  
44.    }  
45.    public override void OnSelect(BaseEventData eventData)  
46.    {  
47.        if (onSelect != null) onSelect(gameObject);  
48.    }  
49.    public override void OnUpdateSelected(BaseEventData eventData)  
50.    {  
51.        if (onUpdateSelect != null) onUpdateSelect(gameObject);  
52.    }  
53.  
54.    public override void OnDrag(PointerEventData eventData)  
55.    {  
56.        if (onDrag != null) onDrag(gameObject);  
57.    }  
58.  
59.    public override void OnDrop(PointerEventData eventData)  
60.    {  
61.        if (onDrop != null) onDrop(gameObject);  
62.    }  
63.  
64.    public override void OnDeselect(BaseEventData eventData)  
65.    {  
66.        if (onDeselect != null) onDeselect(gameObject);  
67.    }  
68.  
69.    public override void OnScroll(PointerEventData eventData)  
70.    {  
71.        if (onScroll != null) onScroll(gameObject);  
72.    }  
73.  
74.    public override void OnMove(AxisEventData eventData)  
75.    {  
76.        if (onMove != null) onMove(gameObject);  
77.    }  
78.  
79.    public override void OnInitializePotentialDrag(PointerEventData eventData)  
80.    {  
81.        if (onInitializePotentialDrag != null) onInitializePotentialDrag(gameObject);  
82.    }  
83.  
84.    public override void OnBeginDrag(PointerEventData eventData)  
85.    {  
86.        if (onBeginDrag != null) onBeginDrag(gameObject);  
87.    }  
88.  
89.    public override void OnEndDrag(PointerEventData eventData)  
90.    {  
91.        if (onEndDrag != null) onEndDrag(gameObject);  
92.    }  
93.  
94.    public override void OnSubmit(BaseEventData eventData)  
95.    {  
96.        if (onSubmit != null) onSubmit(gameObject);  
97.    }  
98.  
99.    public override void OnCancel(BaseEventData eventData)  
100.    {  
101.        if (onCancel != null) onCancel(gameObject);  
102.    }  
103.  
104.    /// <summary>  
105.    /// 获取或添加一个事件侦听器到指定的游戏对象。用法和NGUI一样  
106.    /// </summary>  
107.  
108.    public static EventTriggerListener Get(GameObject go)  
109.    {  
110.        EventTriggerListener listener = go.GetComponent<EventTriggerListener>();  
111.        if (listener == null) listener = go.AddComponent<EventTriggerListener>();  
112.        return listener;  
113.    } 

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触发的机理和时机:

 ①PointerEnter:指针(鼠标、手指等)进入目标(Button、Panel等)范围的瞬间;

 ②PointerExit:指针离开目标范围的瞬间;

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

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

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

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

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

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

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

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

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

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

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

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

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

 ⑯Submit目标处于"Select"状态下时点击"Submit"(默认为"Enter")时触发;

 ⑰Cancel目标处于"Select"状态下时点击"Cancel"(默认为"ESC")时触发;

都是在网上看到的方法,做个汇总而已。

猜你喜欢

转载自blog.csdn.net/weixin_37608784/article/details/80076509