UGUI的事件系統分析

UGUI的源碼仍是很是清晰的,打開源碼能夠發現, 從UGUI的源碼可知:在EventSystem中調用每一幀函數來實現:函數

private void TickModules()
    {
        for (var i = 0; i < m_SystemInputModules.Count; i++)
        {
            if (m_SystemInputModules[i] != null)
                m_SystemInputModules[i].UpdateModule();
        }
    }

這段代碼能夠獲得當前輸入InputModule的position,接着在GetMousePointerEventData函數中存在這一段代碼:code

public void RaycastAll(PointerEventData eventData, List<RaycastResult> raycastResults)
    {
        raycastResults.Clear();
        var modules = RaycasterManager.GetRaycasters();
        for (int i = 0; i < modules.Count; ++i)
        {
            var module = modules[i];
            if (module == null || !module.IsActive())
                continue;

            module.Raycast(eventData, raycastResults);
        }

        raycastResults.Sort(s_RaycastComparer);
    }

你會發現s_RaycastComparer這樣一個函數,該函數就是對全部射線射到的物體進行排序,哈哈,終於找到這個函數了,看看它的實現:orm

private static int RaycastComparer(RaycastResult lhs, RaycastResult rhs)
    {
        if (lhs.module != rhs.module)
        {
            if (lhs.module.eventCamera != null && rhs.module.eventCamera != null && lhs.module.eventCamera.depth != rhs.module.eventCamera.depth)
            {
                // need to reverse the standard compareTo
                if (lhs.module.eventCamera.depth < rhs.module.eventCamera.depth)
                    return 1;
                if (lhs.module.eventCamera.depth == rhs.module.eventCamera.depth)
                    return 0;

                return -1;
            }

            if (lhs.module.sortOrderPriority != rhs.module.sortOrderPriority)
                return rhs.module.sortOrderPriority.CompareTo(lhs.module.sortOrderPriority);

            if (lhs.module.renderOrderPriority != rhs.module.renderOrderPriority)
                return rhs.module.renderOrderPriority.CompareTo(lhs.module.renderOrderPriority);
        }

        if (lhs.sortingLayer != rhs.sortingLayer)
        {
            // Uses the layer value to properly compare the relative order of the layers.
            var rid = SortingLayer.GetLayerValueFromID(rhs.sortingLayer);
            var lid = SortingLayer.GetLayerValueFromID(lhs.sortingLayer);
            return rid.CompareTo(lid);
        }


        if (lhs.sortingOrder != rhs.sortingOrder)
            return rhs.sortingOrder.CompareTo(lhs.sortingOrder);

        if (lhs.depth != rhs.depth)
            return rhs.depth.CompareTo(lhs.depth);

        if (lhs.distance != rhs.distance)
            return lhs.distance.CompareTo(rhs.distance);

        return lhs.index.CompareTo(rhs.index);
    }

來分析下這段代碼的實現:對象

  • 若是Canvas指定了攝像機,就按照攝像機的depth排序。排序

  • 按照sortOrderPriority的順序排序。遞歸

  • 按照renderOrderPriority排索引

  • 按depth排(針對GraphicRaycaster),其餘兩種物理射線(PhysicsRaycaster,Physics2DRaycaster)的depth爲0。接口

  • 按distance排、這裏是針對兩種物理射線的方式,爲射線到物體的距離。事件

  • 按index排,不管是哪一種射線模式,都會將射線碰撞到的UI物體壓入到列表中,這裏的index就是列表的索引值。源碼

如何找到已經實現了該事件的組件?

在ExecuteEvents的類中有這樣一段代碼:

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

這段代碼一直在點擊的gameobject上遞歸尋找它的父類,而後加入到列表當中。只要有一個父類實現了該接口就會觸發該接口事件。而後返回該gameObject。

作實驗的話,能夠在父對象上實現一個接口函數,點擊子對象發現父對象的函數觸發了。本身親測可行。

相關文章
相關標籤/搜索