事件分派器(Event Dispacther)
UI Toolkit有一個Event System它負責監聽事件,這些事件可能來自OS或是Scripts,當事件發生時,EventDispatcher
會使用最適合的分派策略(appropriate dispatching strategy)將事件分派給對應的visual elements。
Visual elements對於一些預設行為以實作多個事件,這些事件在建立,執行時可能會產生一些額外的事件,例如:MouseMoveEvent
會連帶產生一個MouseEnterEvent
與一個MouseLeaveEvent
,這些事件會被放入一個Queue中,當目前的事件處理完之後在依序處理。(MouseMoveEvent
處理完之後才處理連帶產生MouseEnterEvent
與MouseLeaveEvent
)
分派行為(Dispatch Behavior)
每種Event類型都有它自己的分派行為(dispatch behavior),這些行為(behavior)可以被分為三個階段(stage):
Trickles down
: 事件會在這個Trickles down階段發送給elementBubbles up
: 事件會在這個Bubble-up階段發送給elementCancellable
: 事件取消(execution cancelled),停止(stopped)或是阻止(prevented)自己原先的動作。
事件傳播(Event propagation)
事件分派器(event dispatcher
)在選好事件目標(event target
)之後,就會開始計算這個事件的傳播路徑(propagation path
),傳播路徑是一個list,這個list為會收到該事件的Visual elements組成,且這些Elements是經過排序的
。傳播路徑發生的順序:
trickle-down phase
:路徑從visual element tree
的root visual element
開始往下延伸(descends),直到找到事件目標(event target),這個過程稱為trickle-down phase
- 事件目標(event target)接收到事件
bubble-up phase
:事件沿著tree往上延伸(ascends)直到root element
,這個過程稱為bubble-up phase
事件傳播時,會根據不同的type有不同的行為,
- 例如有些event types會忽略
bubble-up phase
,有些event types只會發送給event target。 - 此外,假設有個element被隱藏(hide)或是(停用)disable,那麼這個element就不會收到事件,但是祖先(ancestors)與子孫(descendants)傳播
事件目標(Event Target)
事件的目標是根據event type而定,例如滑鼠事件(mouse event)它的目標一般來說都是最上層被點擊的element;而鍵盤事件(keyboard event)它的目標則是有焦點(focus)的element。
Event.target
:UI Toolkit的events都有一個target屬性,它持有事件發生element的參考(reference),此外這個Event.target
在分派處理(dispatch process)時是不會改變的。Event.currentTarget
:Event.currentTarget
存放目前正在處理event的visual element
滑鼠事件
PickingMode
:大部分的mouse event會使用picking mode來決定它們的target,VisualElement
class有一個pickingMode
屬性來做這件事,其中
PickingMode.Position
(預設): 根據位置矩形(position rectangle)來挑選PickingMode.Ignore
: 防止被mouse event選到- 此外,你可以override
VisualElement.ContainsPoint()
來自定挑選邏輯
Capture events:在MouseDownEvent
之後,一些elements必須捕獲指標位置(pointer position),以確保它接收到所有後續的滑鼠事件,即使游標不再懸停(hovering over)在該element上。例如,當你點擊button、slider或scroll bar時。
element.CaptureMouse()
或是MouseCaptureController.CaptureMouse()
可以獲取滑鼠。MouseCaptureController.ReleaseMouse()
會釋放滑鼠。- 當某個element持有滑鼠時,另外一個element呼叫
CaptureMouse()
的話,原先持有滑鼠的element會收一個MouseCaptureOutEvent
並失去滑鼠- 應用程式中一次只能有一個element捕獲滑鼠。當一個element捕獲了滑鼠時,除了滑鼠滾輪事件(mouse wheel event)之外,它將成為所有後續滑鼠事件的target。(這僅適用於那些尚未設定target且依賴於分派過程來確定targer的滑鼠事件。)
Focus Order
:每個UI Toolkit panel都會有一個 focus ring
,用來決定elements的focus order
,預設是使用depth-first search
(DFS)來決定
- 下圖中的focus order為F,B,A,D,C,E,G,I,H
- 有些events會使用focus order來決定來決定哪些element持有focus,例如鍵盤事件(keyboard event)的目標(target)就是具有焦點(focus)的element
focusable
屬性決定一個visual element是否為可聚焦的(focusable)。預設中,VisualElement
不是focusable的,但它的一些子類(subclass)如TextField
預設是focusable。tabIndex
屬性可以控制focus order,- 預設tabIndex為零,
- 如果tabIndex為負數,則無法使用tab鍵來聚焦在該element上。
- 如果tabIndex為零,則由focus ring algorithm決定。
- 如果tabIndex為正數,則比該element小的element會先被聚焦,之後才是該element。
Reference:https://docs.unity3d.com/Manual/UIE-Events-Dispatching.html