源码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;
}
总结
总的来说这套事件系统还是比较清晰,基于这套我们自己也能扩充更多的事件
|