Manipulators

Manipulators是處理使用者與UI Element交互的State machine,它被用來儲存,註冊,取消註冊event callbacks

建立與使用Manipulators

你不需要自己撰寫管理callback的class,你只需要要繼承UI Toolkit提供的manipulators class就可以使用它們來管理callback與event,步驟如下:

  1. 建立一個class,這個class封裝了針對特定使用者互動所需的事件處理邏輯,並繼承了UI Toolkit提供的manipulators class。
  2. 在這個class中,實作方法(method)來回應相關的互動,例如滑鼠點擊或拖曳。這些方法捕獲並處理必要的資訊以執行這個互動行為(behavior)。
  3. 當你完成設計這個class之後,你就可以實體化它並將其附加到目標(target) UI Element上。這個附加使這個Manipulator class可以攔截和管理指定的事件,並協調使用者互動,同時與你的UI程式碼保持清晰的分離。
  4. 在Visual Element上使用AddManipulator將建立的Manipulator加入到這個Element
  5. 在Visual Element上使用RemoveManipulator為這個Element移除指定的的Manipulator

以下是UI Toolkit提供的Manipulator class
Manipulator 繼承自 描述
Manipulator 所有manipulators的基類(Base class)
KeyboardNavigationManipulator Manipulator 將特定設備輸入事件(device-specific input event)轉換為可以使用鍵盤進行的較高階導航操作(higher-level navigation operations)
MouseManipulator Manipulator 處理滑鼠輸入,擁有一個啟用過濾器(ManipulatorActivationFilter)列表
ContextualMenuManipulator MouseManipulator 當使用者按下滑鼠右鍵或是menu鍵時,顯示內容選單(contextual menu)
PointerManipulator MouseManipulator 處理指標(pointer)輸入,擁有一個啟用過濾器(ManipulatorActivationFilter)列表
Clickable PointerManipulator 追蹤element上的滑鼠事件並辨認是否發生點擊事件,也就是說在同一個element中是否有發生指標按下放開

例子

以下範例將示範

  • 如何一個繼承PointerManipulator,來處理滑鼠輸入,
  • 並使用activators list屬性來設定可以啟用這個manipulator的條件,
    • 例如:當使用者點擊滑鼠左鍵時,啟用這個manipulator
      • 要做到這個,你只要實體化一個ManipulatorActivationFilter,將其button屬性設為MouseButton.LeftMouse並加入到activators list即可
  • 使用target屬性來存取附加這個manipulator的element,
  • Override RegisterCallbacksOnTargetUnregisterCallbacksFromTarget方法用以註冊和取消註冊event callbacks。
建立一個可以讓你拖動element的manipulator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
using UnityEngine;
using UnityEngine.UIElements;

// 繼承PointerManipulator
public class ExampleDragger : PointerManipulator
{
private Vector3 m_Start;
protected bool m_Active;
private int m_PointerId;
private Vector2 m_StartSize;

public ExampleDragger()
{
m_PointerId = -1;
// 實體化一個`ManipulatorActivationFilter`,將其button屬性設為`MouseButton.LeftMouse`並加入到`activators` list
activators.Add(new ManipulatorActivationFilter { button = MouseButton.LeftMouse });
m_Active = false;
}

// Override RegisterCallbacksOnTarget方法用以註冊event callbacks
protected override void RegisterCallbacksOnTarget()
{
target.RegisterCallback<PointerDownEvent>(OnPointerDown);
target.RegisterCallback<PointerMoveEvent>(OnPointerMove);
target.RegisterCallback<PointerUpEvent>(OnPointerUp);
}

// Override UnregisterCallbacksFromTarget方法用以取消註冊event callbacks
protected override void UnregisterCallbacksFromTarget()
{
target.UnregisterCallback<PointerDownEvent>(OnPointerDown);
target.UnregisterCallback<PointerMoveEvent>(OnPointerMove);
target.UnregisterCallback<PointerUpEvent>(OnPointerUp);
}

protected void OnPointerDown(PointerDownEvent e)
{
if (m_Active)
{
e.StopImmediatePropagation();
return;
}

if (CanStartManipulation(e))
{
m_Start = e.localPosition;
m_PointerId = e.pointerId;

m_Active = true;
target.CapturePointer(m_PointerId);
e.StopPropagation();
}
}

protected void OnPointerMove(PointerMoveEvent e)
{
if (!m_Active || !target.HasPointerCapture(m_PointerId))
return;

Vector2 diff = e.localPosition - m_Start;

target.style.top = target.layout.y + diff.y;
target.style.left = target.layout.x + diff.x;

e.StopPropagation();
}

protected void OnPointerUp(PointerUpEvent e)
{
if (!m_Active || !target.HasPointerCapture(m_PointerId) || !CanStopManipulation(e))
return;

m_Active = false;
target.ReleaseMouse();
e.StopPropagation();
}
}
建立一個可以當拖動時,改變element大小的manipulator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
using UnityEngine;
using UnityEngine.UIElements;

public class ExampleResizer : PointerManipulator
{
private Vector3 m_Start;
protected bool m_Active;
private int m_PointerId;
private Vector2 m_StartSize;
public ExampleResizer()
{
m_PointerId = -1;
activators.Add(new ManipulatorActivationFilter { button = MouseButton.LeftMouse });
m_Active = false;
}

protected override void RegisterCallbacksOnTarget()
{
target.RegisterCallback<PointerDownEvent>(OnPointerDown);
target.RegisterCallback<PointerMoveEvent>(OnPointerMove);
target.RegisterCallback<PointerUpEvent>(OnPointerUp);
}

protected override void UnregisterCallbacksFromTarget()
{
target.UnregisterCallback<PointerDownEvent>(OnPointerDown);
target.UnregisterCallback<PointerMoveEvent>(OnPointerMove);
target.UnregisterCallback<PointerUpEvent>(OnPointerUp);
}

protected void OnPointerDown(PointerDownEvent e)
{
if (m_Active)
{
e.StopImmediatePropagation();
return;
}

if (CanStartManipulation(e))
{
m_Start = e.localPosition;
m_StartSize = target.layout.size;
m_PointerId = e.pointerId;
m_Active = true;
target.CapturePointer(m_PointerId);
e.StopPropagation();
}
}

protected void OnPointerMove(PointerMoveEvent e)
{
if (!m_Active || !target.HasPointerCapture(m_PointerId))
return;

Vector2 diff = e.localPosition - m_Start;

target.style.height = m_StartSize.y + diff.y;
target.style.width = m_StartSize.x + diff.x;

e.StopPropagation();
}

protected void OnPointerUp(PointerUpEvent e)
{
if (!m_Active || !target.HasPointerCapture(m_PointerId) || !CanStopManipulation(e))
return;

m_Active = false;
target.ReleasePointer(m_PointerId);
m_PointerId = -1;
e.StopPropagation();
}
}
加入manipulator
1
2
3
4
var myElement = new VisualElement();

// 加入manipulator到這個VisualElement
myElement.AddManipulator(new ExampleDragger());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var box = new VisualElement()
{
style =
{
left = 100,
top = 100,
width = 100,
height = 100,
backgroundColor = Color.red
},
pickingMode = PickingMode.Position,
};

box.AddManipulator(new ExampleResizer());
移除manipulator
1
2
// 為這個VisualElement移除manipulator
myElement.RemoveManipulator<ExampleDragger>();

評論