0%

Unity3D UGUI 源码学习 ExecuteEvents

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的实例(事件)。该委托的实例会传入两个参数,handlereventData,而该方法的内容就是调用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