Unity3D_UGUI|UIGU源码分析3 (ExecuteEvents)

源码3:ExecuteEvents 上面在分析 输入模块的时候 都提到了会有对应的事件发送。具体的实现就在ExecuteEvents 类里面
下面我们来分析一下这个事件系统
在最上面 有一个委托定义

public delegate void EventFunction(T1 handler, BaseEventData eventData);

带有两个参数 一个是handler 是个泛型 一个是eventData通常这个会包含位置信息 偏移量 点击物体等等
基于这个委托 在当前类定义了很多委托的实例 (下面放了部分原始代码)
private static readonly EventFunction s_PointerEnterHandler = Execute; private static void Execute(IPointerEnterHandler handler, BaseEventData eventData) { handler.OnPointerEnter(ValidateEventData(eventData)); }private static readonly EventFunction s_PointerExitHandler = Execute; private static void Execute(IPointerExitHandler handler, BaseEventData eventData) { handler.OnPointerExit(ValidateEventData(eventData)); }private static readonly EventFunction s_PointerDownHandler = Execute; private static void Execute(IPointerDownHandler handler, BaseEventData eventData) { handler.OnPointerDown(ValidateEventData(eventData)); }private static readonly EventFunction s_PointerUpHandler = Execute; private static void Execute(IPointerUpHandler handler, BaseEventData eventData) { handler.OnPointerUp(ValidateEventData【Unity3D_UGUI|UIGU源码分析3 (ExecuteEvents)】(eventData)); }

从这里看出来 上面有很多具体的handler类型,这些handler 也都是一个interface 并且是继承IEventSystemHandler 。同时定义了自己的具体方法。
所以从这里就不难看出来 UI上的具体行为事件 就是通过调用这些handler接口实现的。(上面代码看不明白的就得去熟悉下c# 委托相关的类容)
Execute 具体调用上面的委托实例就是通过下面代码实现了
private static readonly ObjectPool> s_HandlerListPool = new ObjectPool>(null, l => l.Clear()); public static bool Execute(GameObject target, BaseEventData eventData, EventFunction functor) where T : IEventSystemHandler { var internalHandlers = s_HandlerListPool.Get(); GetEventList(target, internalHandlers); //if (s_InternalHandlers.Count > 0) //Debug.Log("Executinng " + typeof (T) + " on " + target); var internalHandlersCount = internalHandlers.Count; for (var i = 0; i < internalHandlersCount; 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; }

上面代码思路是:
1.定义一个对象池 每次执行前 先从对象池中获取List ,上面讲过所有的操作事件都是IEventSystemHandler接口的子类
2.获取当前对象上所有的IEventSystemHandler 返回到上面的List集合中
/// /// Get the specified object's event event. /// private static void GetEventList(GameObject go, IList results) where T : IEventSystemHandler { // Debug.LogWarning("GetEventList<" + typeof(T).Name + ">"); if (results == null) throw new ArgumentException("Results array is null", "results"); if (go == null || !go.activeInHierarchy) return; var components = ListPool.Get(); go.GetComponents(components); var componentsCount = components.Count; for (var i = 0; i < componentsCount; i++) { if (!ShouldSendToComponent(components[i])) continue; // Debug.Log(string.Format("{2} found! On {0}.{1}", go, s_GetComponentsScratch[i].GetType(), typeof(T))); results.Add(components[i] as IEventSystemHandler); } ListPool.Release(components);

3.遍历获取到的IEventSystemHandler ,将handler作为第一个参数,eventData作为第二个参数 执行EventFunction方法,也就是上面讲的委托实例。它会调用handler中对应接口的方法
例如在TouchInputModule中我们调用松开事件
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);

ExecuteHierarchy 与Execute方法类似 这里面还定义了一个ExecuteHierarchy执行事件方法
/// /// Execute the specified event on the first game object underneath the current touch. /// private static readonly List s_InternalTransformList = new List(30); public static GameObject ExecuteHierarchy(GameObject root, BaseEventData eventData, EventFunction callbackFunction) where T : IEventSystemHandler { GetEventChain(root, s_InternalTransformList); var internalTransformListCount = s_InternalTransformList.Count; for (var i = 0; i < internalTransformListCount; i++) { var transform = s_InternalTransformList[i]; if (Execute(transform.gameObject, eventData, callbackFunction)) return transform.gameObject; } return null; }

private static void GetEventChain(GameObject root, IList eventChain) { eventChain.Clear(); if (root == null) return; var t = root.transform; while (t != null) { eventChain.Add(t); t = t.parent; } }

实际上他最终的执行还是通过Execute 方法 ,不过不同点就在与他执行前先沿着Hierarchy获取了包括当前物体以及往上的所有父对象。然后遍历查询这些对项 直到有handler为止。
不过可以想象 这样做的话 下层层级对象的事件肯定会阻挡上层层级对象的事件。
其他方法
//判断对象能否接受对应事件 /// /// Whether the specified game object will be able to handle the specified event. /// public static bool CanHandleEvent(GameObject go) where T : IEventSystemHandler { var internalHandlers = s_HandlerListPool.Get(); GetEventList(go, internalHandlers); var handlerCount = internalHandlers.Count; s_HandlerListPool.Release(internalHandlers); return handlerCount != 0; }//获取实际能接受对应事件的对象 /// /// Bubble the specified event on the game object, figuring out which object will actually receive the event. /// public static GameObject GetEventHandler(GameObject root) where T : IEventSystemHandler { if (root == null) return null; Transform t = root.transform; while (t != null) { if (CanHandleEvent(t.gameObject)) return t.gameObject; t = t.parent; }

总结 总的来说这套事件系统还是比较清晰,基于这套我们自己也能扩充更多的事件

    推荐阅读