分派事件(Dispatch event)

事件分派器(Event Dispacther)

UI Toolkit有一個Event System它負責監聽事件,這些事件可能來自OS或是Scripts,當事件發生時,EventDispatcher會使用最適合的分派策略(appropriate dispatching strategy)將事件分派給對應的visual elements。

Visual elements對於一些預設行為以實作多個事件,這些事件在建立,執行時可能會產生一些額外的事件,例如:MouseMoveEvent會連帶產生一個MouseEnterEvent與一個MouseLeaveEvent這些事件會被放入一個Queue中,當目前的事件處理完之後在依序處理。(MouseMoveEvent處理完之後才處理連帶產生MouseEnterEventMouseLeaveEvent)

分派行為(Dispatch Behavior)

每種Event類型都有它自己的分派行為(dispatch behavior),這些行為(behavior)可以被分為三個階段(stage):

  1. Trickles down: 事件會在這個Trickles down階段發送給element
  2. Bubbles up: 事件會在這個Bubble-up階段發送給element
  3. Cancellable: 事件取消(execution cancelled),停止(stopped)或是阻止(prevented)自己原先的動作。

事件傳播(Event propagation)

事件分派器(event dispatcher)在選好事件目標(event target)之後,就會開始計算這個事件的傳播路徑(propagation path),傳播路徑是一個list,這個list為會收到該事件的Visual elements組成,且這些Elements是經過排序的。傳播路徑發生的順序:

  1. trickle-down phase:路徑從visual element treeroot visual element開始往下延伸(descends),直到找到事件目標(event target),這個過程稱為trickle-down phase
  2. 事件目標(event target)接收到事件
  3. 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.currentTargetEvent.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

評論