1. 程式人生 > >UGUI核心大探究(二)執行事件

UGUI核心大探究(二)執行事件

UGUI核心大探究(一)EventSystem我們探究了事件系統,其中我們講到EventSystem可以通過ExecuteEvents這個類來執行事件,那麼事件是如何執行的呢?這裡涉及到了兩個檔案EventInterface和ExecuteEvents。

EventInterface聲明瞭一系列interface(可以參考我之前的部落格關於介面的介紹),如果經常接觸UI的話,我相信你對這些介面一定不陌生。例如IPointerEnterHandler(指標進入事件介面)。一個元件新增這個介面的繼承之後,再實現OnPointerEnter方法,便可以接收到指標進入事件,也就是當滑鼠滑入物件所在的區域之後,便會回撥OnPointerEnter方法。這些介面全都繼承自IEventSystemHandler,而後者也是宣告在EventInterface裡的介面。

以上這些介面都會在ExecuteEvents裡被呼叫。ExecuteEvents類是個靜態類,不能被例項化,所有的公共方法都通過ExecuteEvents.XXXX來呼叫。ExecuteEvents裡聲明瞭一個delegate的型別(可以參考我之前的部落格關於委託的介紹EventFunction,這是一個泛型委託,委託的第一個引數handler可以是不同的型別。然後對EventInterface裡除了IEventSystemHandler外每一個介面聲明瞭一個EventFunction型別的委託變數和方法。例如:

        private static readonly EventFunction<IPointerEnterHandler> s_PointerEnterHandler = Execute;

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


就是聲明瞭一個引數型別為IPointerEnterHandler的委託變數s_PointerEnterHandler,並實現了委託所執行的方法Execute。

然後又聲明瞭一系列屬性,這些屬性是獲取上述委託變數的只讀屬性,用於在外部呼叫。

而外部統一呼叫執行事件的方法是

public static bool Execute<T>(GameObject target, BaseEventData eventData, EventFunction<T> functor) where T : IEventSystemHandler
我們先看一下它的使用方法,例如在BaseInputModule
裡,我們看到:
ExecuteEvents.Execute(t.gameObject, currentPointerData, ExecuteEvents.pointerEnterHandler);

前兩個引數很好理解,第三個引數就是呼叫了ExecuteEvents裡的pointerEnterHandler屬性(也就是上面的s_PointerEnterHandler),這樣泛型T也就變成了IPointerEnterHandler。

Execute方法裡面,通過GetEventList獲得target上的T型別的元件列表,然後遍歷這些元件,並執行

functor(arg, eventData);

pointerEnterHandler為例,我們可以瞭解這個方法實際上執行的是:
arg.OnPointerEnter(ValidateEventData<PointerEventData>(eventData));

也就是呼叫了IPointerEnterHandler型別的元件的OnPointerEnter方法。

至此,我們就瞭解到了UGUI裡的事件是如何執行的:指定某個介面型別,由Execute方法呼叫目標物件的介面方法。

接著,補充一下ExecuteEvents類裡面其他方法的介紹。

ExecuteHierarchy方法會通過GetEventChain獲取target的所以父物件,並對這些物件(包括target)執行Execute方法。
GetEventHandler會遍歷目標物件及其父物件,判斷他們是否包含某個指定介面,如果包含則作為返回值返回。而判斷方法是CanHandleEvent,通過GetEventList方法獲取target上的T型別的元件列表,判斷列表數量不為零。
GetEventHandler主要在輸入模組裡被呼叫,用於獲取某個輸入事件的響應物件。(詳細分析會在後續的文章中介紹)