总结下从网上看到的大部分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"键)时触发;
都是在网上看到的方法,做个汇总而已。