UIGU源码分析3 :ExecuteEvents

源码3:ExecuteEvents

上面在分析 输入模块的时候 都提到了会有对应的事件发送。具体的实现就在ExecuteEvents 类里面

下面我们来分析一下这个事件系统

在最上面 有一个委托定义

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

带有两个参数 一个是handler 是个泛型 一个是eventData通常这个会包含位置信息 偏移量 点击物体等等

基于这个委托 在当前类定义了很多委托的实例 (下面放了部分原始代码)

private static readonly EventFunction<IPointerEnterHandler> s_PointerEnterHandler = Execute;

private static void Execute(IPointerEnterHandler handler, BaseEventData eventData)
{
	handler.OnPointerEnter(ValidateEventData<PointerEventData>(eventData));
}

private static readonly EventFunction<IPointerExitHandler> s_PointerExitHandler = Execute;

private static void Execute(IPointerExitHandler handler, BaseEventData eventData)
{
	handler.OnPointerExit(ValidateEventData<PointerEventData>(eventData));
}

private static readonly EventFunction<IPointerDownHandler> s_PointerDownHandler = Execute;

private static void Execute(IPointerDownHandler handler, BaseEventData eventData)
{
	handler.OnPointerDown(ValidateEventData<PointerEventData>(eventData));
}

private static readonly EventFunction<IPointerUpHandler> s_PointerUpHandler = Execute;

private static void Execute(IPointerUpHandler handler, BaseEventData eventData)
{
	handler.OnPointerUp(ValidateEventData<PointerEventData>(eventData));
}

从这里看出来 上面有很多具体的handler类型,这些handler 也都是一个interface 并且是继承IEventSystemHandler 。同时定义了自己的具体方法。

所以从这里就不难看出来 UI上的具体行为事件 就是通过调用这些handler接口实现的。(上面代码看不明白的就得去熟悉下c# 委托相关的类容)

Execute

具体调用上面的委托实例就是通过下面代码实现了

    private static readonly ObjectPool<List<IEventSystemHandler>> s_HandlerListPool = new ObjectPool<List<IEventSystemHandler>>(null, l => l.Clear());

    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);

        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集合中

        /// <summary>
        /// Get the specified object's event event.
        /// </summary>
        private static void GetEventList<T>(GameObject go, IList<IEventSystemHandler> 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<Component>.Get();
            go.GetComponents(components);

            var componentsCount = components.Count;
            for (var i = 0; i < componentsCount; i++)
            {
                if (!ShouldSendToComponent<T>(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<Component>.Release(components);
          

3.遍历获取到的IEventSystemHandler ,将handler作为第一个参数,eventData作为第二个参数 执行EventFunction方法,也就是上面讲的委托实例。它会调用handler中对应接口的方法

例如在TouchInputModule中我们调用松开事件

 ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);

ExecuteHierarchy

与Execute方法类似 这里面还定义了一个ExecuteHierarchy执行事件方法

        /// <summary>
        /// Execute the specified event on the first game object underneath the current touch.
        /// </summary>
        private static readonly List<Transform> s_InternalTransformList = new List<Transform>(30);

        public static GameObject ExecuteHierarchy<T>(GameObject root, BaseEventData eventData, EventFunction<T> 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<Transform> eventChain)
    {
        eventChain.Clear();
        if (root == null)
            return;

        var t = root.transform;
        while (t != null)
        {
            eventChain.Add(t);
            t = t.parent;
        }
    }

实际上他最终的执行还是通过Execute 方法 ,不过不同点就在与他执行前先沿着Hierarchy获取了包括当前物体以及往上的所有父对象。然后遍历查询这些对项 直到有handler为止。

不过可以想象 这样做的话 下层层级对象的事件肯定会阻挡上层层级对象的事件。

其他方法

    //判断对象能否接受对应事件
    /// <summary>
    /// Whether the specified game object will be able to handle the specified event.
    /// </summary>
    public static bool CanHandleEvent<T>(GameObject go) where T : IEventSystemHandler
    {
        var internalHandlers = s_HandlerListPool.Get();
        GetEventList<T>(go, internalHandlers);
        var handlerCount = internalHandlers.Count;
        s_HandlerListPool.Release(internalHandlers);
        return handlerCount != 0;
    }

//获取实际能接受对应事件的对象
    /// <summary>
    /// Bubble the specified event on the game object, figuring out which object will actually receive the event.
    /// </summary>
    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;
        }

总结

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

猜你喜欢

转载自blog.csdn.net/NippyLi/article/details/123241996