UGUI中Button添加事件大总结(有参,无参,动态)
发表于2018-06-13
总结了从网上看到的大部分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")检测);
(13)InitializePotentialDrag:指针在目标范围内按下时:初始化潜在的可拖动目标,在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