当前位置:   article > 正文

【Unity知识点详解】Button点击事件拓展,单击、双击、长按实现_unity button onclick

unity button onclick

Button拓展

        今天来聊一下关于Button的事件拓展,这里只是拿Button来举例,Unity中其他的UI组件如Toggle、Slider等都也适用。

        我们知道在Button中我们可以通过onClick的方式来添加点击事件,但在游戏开发过程中我们往往对Button有着更多的功能需求,比如说双击、长按、按钮按下、按钮弹起等。这里举一个游戏中实际的例子,在游戏背包中的道具,单击道具时我们需要显示道具的tips框,双击时我们会去使用道具,长按时我们则可以拖动道具,当长按弹起时则道具回到原位或移动到新格子内。虽然这里的背包道具不是按钮,但在单个UI组件上集合了单击、双击、长按、按钮弹起等事件的响应。接下来将介绍如何拓展UI组件来实现这些功能。

        首先我们来认识一下Selectable这个类,Selectable是所有交互组件的基类,Unity原生的Button组件就是继承了Selectable,我们要拓展Button功能也是对Selectable下的OnPointerDown、OnPointerUp等接口进行重写。

        话不多说先上代码,代码有点长大家可以先跳过细节,后面慢慢讲解。

  1. using System;
  2. using UnityEngine;
  3. using UnityEngine.UI;
  4. using UnityEngine.EventSystems;
  5. public class ExButton : Button
  6. {
  7. private enum EnumExButtonState
  8. {
  9. /// <summary></summary>
  10. None,
  11. /// <summary>鼠标按下</summary>
  12. PointerDown,
  13. /// <summary>鼠标按下</summary>
  14. PointerUp,
  15. /// <summary>单击</summary>
  16. Click,
  17. /// <summary>双击</summary>
  18. DoubleClick,
  19. /// <summary>长按开始</summary>
  20. PressBegin,
  21. /// <summary>长按</summary>
  22. Press,
  23. /// <summary>长按结束</summary>
  24. PressEnd,
  25. }
  26. /// <summary>按钮状态</summary>
  27. private EnumExButtonState mButtonState = EnumExButtonState.None;
  28. /// <summary>鼠标按下时间</summary>
  29. private float mPointerDownTime = 0.0f;
  30. [SerializeField]
  31. /// <summary>双击间隔时间</summary>
  32. private float mDoubleClickInterval = 0.2f;
  33. [SerializeField]
  34. /// <summary>长按开始时间</summary>
  35. private float mPressBeginTime = 0.3f;
  36. [SerializeField]
  37. /// <summary>长按间隔时间,0为每帧调用</summary>
  38. private float mPressIntervalTime = 0.2f;
  39. /// <summary>长按缓存时间</summary>
  40. private float mPressCacheTime = 0f;
  41. public Action OnClick { get; set; }
  42. public Action OnDoubleClick { get; set; }
  43. public Action OnPressBegin { get; set; }
  44. public Action OnPress { get; set; }
  45. public Action OnPressEnd { get; set; }
  46. public override void OnPointerDown(PointerEventData eventData)
  47. {
  48. base.OnPointerDown(eventData);
  49. if (OnDoubleClick != null)
  50. {
  51. if (mButtonState == EnumExButtonState.None)
  52. {
  53. mButtonState = EnumExButtonState.PointerDown;
  54. mPointerDownTime = Time.time;
  55. }
  56. else if (mButtonState == EnumExButtonState.PointerUp)
  57. {
  58. if (Time.time - mPointerDownTime < mDoubleClickInterval)
  59. {
  60. mButtonState = EnumExButtonState.DoubleClick;
  61. return;
  62. }
  63. else
  64. {
  65. mButtonState = EnumExButtonState.PointerDown;
  66. mPointerDownTime = Time.time;
  67. }
  68. }
  69. }
  70. if (OnPressBegin != null || OnPress != null || OnPressEnd != null)
  71. {
  72. if (mButtonState != EnumExButtonState.DoubleClick)
  73. {
  74. mButtonState = EnumExButtonState.PointerDown;
  75. mPointerDownTime = Time.time;
  76. }
  77. }
  78. if (OnClick != null)
  79. {
  80. mButtonState = EnumExButtonState.PointerDown;
  81. }
  82. }
  83. public override void OnPointerUp(PointerEventData eventData)
  84. {
  85. base.OnPointerUp(eventData);
  86. if (OnDoubleClick != null)
  87. {
  88. if (mButtonState == EnumExButtonState.PointerDown)
  89. {
  90. mButtonState = EnumExButtonState.PointerUp;
  91. return;
  92. }
  93. else if (mButtonState == EnumExButtonState.DoubleClick)
  94. {
  95. return;
  96. }
  97. }
  98. if (OnPressBegin != null || OnPress != null || OnPressEnd != null)
  99. {
  100. if (mButtonState == EnumExButtonState.Press)
  101. {
  102. mButtonState = EnumExButtonState.PressEnd;
  103. return;
  104. }
  105. }
  106. if (OnClick != null)
  107. {
  108. if (mButtonState == EnumExButtonState.PointerDown)
  109. mButtonState = EnumExButtonState.PointerUp;
  110. }
  111. }
  112. private void Update()
  113. {
  114. ProcessUpdate();
  115. ResponseButtonState();
  116. }
  117. private void ProcessUpdate()
  118. {
  119. if (OnDoubleClick != null) { }
  120. if (OnPressBegin != null || OnPress != null || OnPressEnd != null)
  121. {
  122. if (mButtonState == EnumExButtonState.PointerDown)
  123. {
  124. if (Time.time - mPointerDownTime > mPressBeginTime)
  125. {
  126. mButtonState = EnumExButtonState.PressBegin;
  127. mPressCacheTime = 0f;
  128. return;
  129. }
  130. }
  131. }
  132. if (OnClick != null)
  133. {
  134. if (mButtonState == EnumExButtonState.PointerUp)
  135. {
  136. if (OnDoubleClick != null)
  137. {
  138. if (Time.time - mPointerDownTime > mDoubleClickInterval)
  139. mButtonState = EnumExButtonState.Click;
  140. }
  141. else
  142. {
  143. mButtonState = EnumExButtonState.Click;
  144. }
  145. }
  146. }
  147. }
  148. private void ResponseButtonState()
  149. {
  150. switch (mButtonState)
  151. {
  152. case EnumExButtonState.None:
  153. break;
  154. case EnumExButtonState.Click:
  155. OnClick?.Invoke();
  156. mButtonState = EnumExButtonState.None;
  157. break;
  158. case EnumExButtonState.DoubleClick:
  159. OnDoubleClick?.Invoke();
  160. mButtonState = EnumExButtonState.None;
  161. break;
  162. case EnumExButtonState.PressBegin:
  163. OnPressBegin?.Invoke();
  164. mButtonState = EnumExButtonState.Press;
  165. break;
  166. case EnumExButtonState.Press:
  167. {
  168. mPressCacheTime += Time.deltaTime;
  169. if (mPressCacheTime >= mPressIntervalTime)
  170. {
  171. mPressCacheTime = mPressCacheTime - mPressIntervalTime;
  172. OnPress?.Invoke();
  173. }
  174. break;
  175. }
  176. case EnumExButtonState.PressEnd:
  177. OnPressEnd?.Invoke();
  178. mButtonState = EnumExButtonState.None;
  179. break;
  180. default:
  181. break;
  182. }
  183. }
  184. }

        ExButton组件功能的拓展需要继承自Button类,并且重写OnPointerDown、OnPointerUp方法(这里根据需求只重写了OnPointerDown、OnPointerUp方法,大家可以根据自己的需求重写Selectable下的方法)。根据需求我们要实现点击、双击、长按、长按开始、长按结束事件的回调,所以在代码中我们提供了OnClick、OnDoubleClick、OnPressBegin、OnPress、OnPressEnd回调方法。

  1. public Action OnClick { get; set; }
  2. public Action OnDoubleClick { get; set; }
  3. public Action OnPressBegin { get; set; }
  4. public Action OnPress { get; set; }
  5. public Action OnPressEnd { get; set; }

        逻辑采用了单状态机来实现,在OnPointerDown、OnPointerUp、Update方法中去改变成员mButtonState的状态,最终在ResponseButtonState方法中根据mButtonState的状态去进行事件的回调。

        在逻辑中也进行了事件回调的优化处理,当OnClick、OnDoubleClick、OnPressBegin、OnPress、OnPressEnd所有回调都被注册时,会优先处理OnDoubleClick,其次是OnPressBegin、OnPress、OnPressEnd,最后才是OnClick。例如当OnDoubleClick未被注册时,则会跳过OnDoubleClick对应的逻辑判断,提前处理并响应其他回调事件。

        

base.OnPointerDown、base.OnPointerUp

  1. public override void OnPointerDown(PointerEventData eventData)
  2. {
  3. base.OnPointerDown(eventData);
  4. }
  5. public override void OnPointerUp(PointerEventData eventData)
  6. {
  7. base.OnPointerUp(eventData);
  8. }

        在重写OnPointerDown、OnPointerUp后如需保留原有功能,需要调用base.OnPointerDown、base.OnPointerUp方法。只有调用基类方法,按钮的按下颜色改变才会有效果,当然这些基类方法也可以在别处调用。

官方文档连接

Selectable文档连接:https://docs.unity3d.com/Packages/com.unity.ugui@2.0/manual/script-Selectable.html

Selectable类API文档连接:https://docs.unity3d.com/Packages/com.unity.ugui@2.0/api/UnityEngine.UI.Selectable.html?q=selectable

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/762773
推荐阅读
相关标签
  

闽ICP备14008679号