[Selectable]
Button/Dropdown/InputField/Scrollbar/Slider/Toggle都是继承Selectable实现,Transition实现状态间切换。
public class Selectable
:
UIBehaviour,
IMoveHandler,
IPointerDownHandler, IPointerUpHandler,
IPointerEnterHandler, IPointerExitHandler,
ISelectHandler, IDeselectHandler
{}
protected enum SelectionState
{
Normal,
Highlighted,
Pressed,
Disabled
}
public enum Transition
{
None,
ColorTint,
SpriteSwap,
Animation
}
[EventSystem]
EventSystem管理所有BaseInputModule,系统支持且激活启用的Module被调用Process,PointerEventData和Raycast的结果传给Module去处理,BaseInputModule通知具体的IEventSystemHandler进行逻辑处理(ExecuteEvents)。
EventData:
BaseEventData实现AbstractEventData
PointerEventData:点击触摸相关数据
AxisEventData:移动方向和量
[StandaloneInputModule]
StandaloneInputModule->PointerInputModule->BaseInputModule
ProcessMouseEvent:鼠标左中右键处理ProcessMousePress,ProcessMove,ProcessDrag
ProcessTouchEvents:多点触摸处理ProcessTouchPress,ProcessMove,ProcessDrag
均产生PointerEventData符合条件的交予ExecuteEvents执行事件。
[Raycasters]
如下图可可知事件处理中,性能最大消耗点在BaseRaycaster.Raycast
如下代码可知即使未勾选raycastTarget也会参与到遍历中,访问频次集中在depth和RectangleContainsScreenPoint以及sort排序。
private static void Raycast(Canvas canvas, Camera eventCamera, Vector2 pointerPosition, IList<Graphic> foundGraphics, List<Graphic> results)
{
// Debug.Log("ttt" + pointerPoision + ":::" + camera);
// Necessary for the event system
int totalCount = foundGraphics.Count;
for (int i = 0; i < totalCount; ++i)
{
Graphic graphic = foundGraphics[i];
// -1 means it hasn't been processed by the canvas, which means it isn't actually drawn
if (graphic.depth == -1 || !graphic.raycastTarget || graphic.canvasRenderer.cull)
continue;
if (!RectTransformUtility.RectangleContainsScreenPoint(graphic.rectTransform, pointerPosition, eventCamera))
continue;
if (graphic.Raycast(pointerPosition, eventCamera))
{
s_SortedGraphics.Add(graphic);
}
}
s_SortedGraphics.Sort((g1, g2) => g2.depth.CompareTo(g1.depth));
// StringBuilder cast = new StringBuilder();
totalCount = s_SortedGraphics.Count;
for (int i = 0; i < totalCount; ++i)
results.Add(s_SortedGraphics[i]);
// Debug.Log (cast.ToString());
s_SortedGraphics.Clear();
}
}
[EventSystemHandler]
事件处理者,需要触发哪个事件就实现哪个接口
主要分为三大类:
IPointerXXXXXHandler
IXXXXXDragHandler
IXXXXXHandler
[ExecuteEvents]
遍历所有实现的事件接口,执行事件。
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;
}
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);
for (var i = 0; i < components.Count; 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);
// Debug.LogWarning("end GetEventList<" + typeof(T).Name + ">");
}