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
我們先看一下它的使用方法,例如在BaseInputModuleExecuteEvents.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主要在輸入模組裡被呼叫,用於獲取某個輸入事件的響應物件。(詳細分析會在後續的文章中介紹)