unity UGUI 源码分析(1) EventSystem

顶层上来看EventSystem继承于UIBehaviour,UIBehaviour继承于Monobehavior所有包含了Update等方法。Update方法首先更新输入模块状态,然后选定当前可用的输入模块,最后调用输入模块的Process方法。

protected virtual void Update()
{
    if (current != this)
        return;
    TickModules();//该方法用于更新输入模块的状态,例如鼠标的位置
    bool changedModule = false;
    var systemInputModulesCount = m_SystemInputModules.Count;
    for (var i = 0; i < systemInputModulesCount; i++)
    {
        var module = m_SystemInputModules[i];
        if (module.IsModuleSupported() && module.ShouldActivateModule())
        {
            if (m_CurrentInputModule != module)
            {
                ChangeEventModule(module);
                changedModule = true;
            }
            break;
        }
    }
    // no event module set... set the first valid one...
    if (m_CurrentInputModule == null)
    {
        for (var i = 0; i < systemInputModulesCount; i++)
        {
            var module = m_SystemInputModules[i];
            if (module.IsModuleSupported())
            {
                ChangeEventModule(module);
                changedModule = true;
                break;
            }
        }
    }
    if (!changedModule && m_CurrentInputModule != null)
        m_CurrentInputModule.Process();//上面两个循环用于确定使用哪个输入模块,Process方法用//于发送事件

输入模块以StandaloneInputModule为例。StandaloneInputModule中的Process方法如下:其中ProcessMouseEvent用于发送鼠标事件,ProcessMouseEvent方法首先通过GetMousePointerEventData方法会调用射线检测确定当前选中的GameObject,然后会处理鼠标按压、移动、拖拽等事件。Process方法中的SendXXXEventToSelectedObject方法负责通知EventSystem中当前被选中的物体执行相应事件。

public override void Process()
{
    if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus())
        return;

    bool usedEvent = SendUpdateEventToSelectedObject();

    // case 1004066 - touch / mouse events should be processed before navigation events in case
    // they change the current selected gameobject and the submit button is a touch / mouse button.

    // touch needs to take precedence because of the mouse emulation layer
    if (!ProcessTouchEvents() && input.mousePresent)
        ProcessMouseEvent();

    if (eventSystem.sendNavigationEvents)
    {
        if (!usedEvent)
            usedEvent |= SendMoveEventToSelectedObject();

        if (!usedEvent)
            SendSubmitEventToSelectedObject();
    }
}
protected void ProcessMouseEvent(int id)
{
    var mouseData = GetMousePointerEventData(id);
    var leftButtonData = mouseData.GetButtonState(PointerEventData.InputButton.Left).eventData;

    m_CurrentFocusedGameObject = leftButtonData.buttonData.pointerCurrentRaycast.gameObject;

    // Process the first mouse button fully
    ProcessMousePress(leftButtonData);
    ProcessMove(leftButtonData.buttonData);
    ProcessDrag(leftButtonData.buttonData);

    // Now process right / middle clicks
    ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData);
    ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData.buttonData);
    ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData);
    	ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData.buttonData);

    if (!Mathf.Approximately(leftButtonData.buttonData.scrollDelta.sqrMagnitude, 0.0f))
    {
        var scrollHandler = ExecuteEvents.GetEventHandler<IScrollHandler>(leftButtonData.buttonData.pointerCurrentRaycast.gameObject);
        ExecuteEvents.ExecuteHierarchy(scrollHandler, leftButtonData.buttonData, ExecuteEvents.scrollHandler);
    }
}

最主要关注这一个方法。

ExecuteEvents.Execute(pointerEvent.pointerDrag,pointerEvent,ExecuteEvents.initializePotentialDrag);

Execute方法就是执行事件。我们跳转到Execute的定义可以发现它包含三个参数,第一个参数为target是GameObject类型,第二个参数主要包含了事件的一些信息,第三个参数类型为EventFuction<T>是一个委托,定义如下:

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

所以可以很容易分析出Execute方法的功能

1:首先找到target (GameObject)中类型为T(一个接口)的component,保存到internalHandlers中

2:然后遍历internalHandlers这个List,执行 functor

3:functor有很多重载会根据输入的类型T,去执行T接口中的对应方法。

private static readonly EventFunction<IPointerDownHandler> s_PointerDownHandler = Execute;

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

所以在使用的时候我们只需要在脚本中实现这些方法就可以被事件调用了。综上所示EventSystem分析完毕。

public static bool Execute<T>(GameObject target, BaseEventData eventData, EventFunction<T> functor) where T : IEventSystemHandler
{
    var internalHandlers = ListPool<IEventSystemHandler>.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;
    ListPool<IEventSystemHandler>.Release(internalHandlers);
    return handlerCount > 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值