ExecuteEvents
是EventSystem的一部分。在InputModule产生事件,Raycaster确定接收对象之后,ExecuteEvents
提供了用于向确定的GameObject发送事件的静态方法Execute(...)
。
在开始ExecuteEvents
之前,不得不先提到EventInterfaces。
EventInterfaces 在EventInterfaces.cs
中定义的有一个接口IEventSystemHandler
及它的17个衍生的接口。详见下边的代码,这17个接口分别对应17种事件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 public interface IEventSystemHandler { } public interface IPointerEnterHandler : IEventSystemHandler { void OnPointerEnter(PointerEventData eventData); } public interface IPointerExitHandler : IEventSystemHandler { void OnPointerExit(PointerEventData eventData); } public interface IPointerDownHandler : IEventSystemHandler { void OnPointerDown(PointerEventData eventData); } public interface IPointerUpHandler : IEventSystemHandler { void OnPointerUp(PointerEventData eventData); } public interface IPointerClickHandler : IEventSystemHandler { void OnPointerClick(PointerEventData eventData); } public interface IBeginDragHandler : IEventSystemHandler { void OnBeginDrag(PointerEventData eventData); } public interface IInitializePotentialDragHandler : IEventSystemHandler { void OnInitializePotentialDrag(PointerEventData eventData); } public interface IDragHandler : IEventSystemHandler { void OnDrag(PointerEventData eventData); } public interface IEndDragHandler : IEventSystemHandler { void OnEndDrag(PointerEventData eventData); } public interface IDropHandler : IEventSystemHandler { void OnDrop(PointerEventData eventData); } public interface IScrollHandler : IEventSystemHandler { void OnScroll(PointerEventData eventData); } public interface IUpdateSelectedHandler : IEventSystemHandler { void OnUpdateSelected(BaseEventData eventData); } public interface ISelectHandler : IEventSystemHandler { void OnSelect(BaseEventData eventData); } public interface IDeselectHandler : IEventSystemHandler { void OnDeselect(BaseEventData eventData); } public interface IMoveHandler : IEventSystemHandler { void OnMove(AxisEventData eventData); } public interface ISubmitHandler : IEventSystemHandler { void OnSubmit(BaseEventData eventData); } public interface ICancelHandler : IEventSystemHandler { void OnCancel(BaseEventData eventData); }
基本上也是之前InputModule中提到过的所有的可响应的事件类型。
Execute与OnXxx() 前边在InputModule的内容中提到过,调用ExecuteEvents.Execute(...)
方法执行了事件的动作。我们就以PointerEnter
为例,来一步一步看看ExecuteEvents
的公有静态方法:
1 public static bool Execute<T>(GameObject target, BaseEventData eventData, EventFunction<T> functor) where T : IEventSystemHandler
是如何与void OnPointerEnter(PointerEventData eventData)
关联起来的。
声明委托类型 首先是在ExecuteEvents
中定义了委托类型EventFunction
,泛型委托接收一个handler
和一个eventData
作为参数。其实之前所有的事件调用函数OnXxx()
都是符合这一委托类型的方法。
1 public delegate void EventFunction<T1>(T1 handler, BaseEventData eventData);
Handler接口和回调方法 刚才说到过的,在EventInterfaces
中定义的17种接口,IPointerEnterHandler
是其中之一:
1 2 3 4 public interface IPointerEnterHandler : IEventSystemHandler { void OnPointerEnter(PointerEventData eventData); }
此接口要求实现回调方法OnPointerEnter
。
声明私有的委托对象 在ExecuteEvents
中声明一个静态私有的方法,作为委托EventFunction
的实例(事件)。该委托的实例会传入两个参数,handler
和eventData
,而该方法的内容就是调用handler.OnPointerEnter(...)
,如下:
1 2 3 4 5 6 private static readonly EventFunction<IPointerEnterHandler> s_PointerEnterHandler = Execute; private static void Execute(IPointerEnterHandler handler, BaseEventData eventData) { handler.OnPointerEnter(ValidateEventData<PointerEventData>(eventData)); }
公有属性来获取私有委托对象 这么做应该就是确保pointerEnterHandler
只读:
1 2 3 4 public static EventFunction<IPointerEnterHandler> pointerEnterHandler { get { return s_PointerEnterHandler; } }
公有静态方法Execute 1 public static bool Execute<T>(GameObject target, BaseEventData eventData, EventFunction<T> functor) where T : IEventSystemHandler
这个就是ExecuteEvents.Execute(...)
了,也是一个泛型方法,注意第三个参数functor
就是之前的对应私有委托对象的公有属性。对应到PointerEnter类型之后就是下边这个样子:
1 ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerClickHandler);
functor
参数的值是ExecuteEvents.pointerClickHandler
,后边会看到在Execute(...)
里边有functor(...)
,这么一调就调到了之前的OnPointerEnter()
ExecuteEvents主要方法 GetEventHandler 当GameObject触发了某事件,获取响应该事件的对象(即挂有实现了对应Handler接口的component的对象)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static GameObject GetEventHandler<T>(GameObject root) where T : IEventSystemHandler { if (root == null) return null; Transform t = root.transform; while (t != null) { if (CanHandleEvent<T>(t.gameObject)) return t.gameObject; t = t.parent; } return null; }
在获取时会从给定的对象开始,自下而上遍历节点树,直到找到第一个可以响应事件的对象并返回。
Execute 前边提到的执行动作的方法,在各InputModule中被使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public static bool Execute<T>(GameObject target, BaseEventData eventData, EventFunction<T> functor) where T : IEventSystemHandler { var internalHandlers = s_HandlerListPool.Get(); GetEventList<T>(target, internalHandlers); // if (s_InternalHandlers.Count > 0) // Debug.Log("Executinng " + typeof (T) + " on " + target); for (var i = 0; i < internalHandlers.Count; i++) { T arg; try { arg = (T)internalHandlers[i]; } catch (Exception e) { var temp = internalHandlers[i]; Debug.LogException(new Exception(string.Format("Type {0} expected {1} received.", typeof(T).Name, temp.GetType().Name), e)); continue; } try { functor(arg, eventData); } catch (Exception e) { Debug.LogException(e); } } var handlerCount = internalHandlers.Count; s_HandlerListPool.Release(internalHandlers); return handlerCount > 0; }
它会获取target
所有可以响应该事件的组件component存入internalHandlers
,然后执行它们的回调方法。最后返回一个bool值internalHandlers
是否为空,即是否有组件可以响应(响应了)这次调用要执行的事件。
ExecuteHierarchy 与Execute
相似,也是执行事件动作。
1 2 3 4 5 6 7 8 9 10 11 12 public static GameObject ExecuteHierarchy<T>(GameObject root, BaseEventData eventData, EventFunction<T> callbackFunction) where T : IEventSystemHandler { GetEventChain(root, s_InternalTransformList); for (var i = 0; i < s_InternalTransformList.Count; i++) { var transform = s_InternalTransformList[i]; if (Execute(transform.gameObject, eventData, callbackFunction)) return transform.gameObject; } return null; }
不同的是,当传入一个GameObject时,不再是当做target使用,而是获取到从改对象到顶级父节点之间所经历的的全部对象GetEventChain
,然后自下而上遍历这些对象,调用Execute
。当有对象可以响应该事件时(Execute
返回true
)则停止并返回该对象。
本系列其它文章详见Unity3D UGUI 源码学习
REFERENCE