Unity PointerEventData详解
UnityEngine.EventSystems.PointerEventData 是 Unity UGUI 事件系统中用于封装指针输入事件(鼠标、触摸、手写笔等)数据的核心类。它继承自 BaseEventData,作为参数传递给各种指针相关的事件接口(如 IPointerClickHandler, IDragHandler, IScrollHandler 等),提供了关于当前指针状态的详细信息。
以下是 PointerEventData 的详细解析:
1. 核心作用
- 数据载体:承载用户通过鼠标点击、触摸屏触摸或手柄模拟指针时产生的所有上下文信息。
- 状态追踪:记录指针从按下、移动、拖拽到抬起的整个生命周期中的关键状态。
- 射线检测信息:包含指针当前指向的 UI 对象或 3D 对象的射线检测结果(RaycastResult)。
2. 常用属性详解
位置与移动
-
position (Vector2):当前指针在屏幕空间中的坐标位置。 -
pressPosition (Vector2):指针最后一次按下(OnPointerDown)时的屏幕坐标。常用于计算拖拽起始点。 -
delta (Vector2):自上一帧以来指针的移动增量。在OnDrag事件中非常有用,用于实现物体跟随鼠标移动。 -
scrollDelta (Vector2):自上一帧以来的滚动增量(通常用于鼠标滚轮或触控板双指滑动)。
点击与按钮
-
button (InputButton):触发当前事件的鼠标按钮类型(左键、右键、中键)。 -
clickCount (int):连续点击的次数。可用于区分单击、双击或多击。 -
clickTime (float):上次发送单击事件的时间戳。 -
pointerId (int):指针的唯一标识符。-1:鼠标左键-2:鼠标右键-3:鼠标中键>= 0:触摸屏的触摸点 ID(支持多点触控)
交互对象与射线检测
-
pointerCurrentRaycast (RaycastResult):当前帧指针射线检测到的结果。包含 hit 的对象、距离、UV 坐标等信息。 -
pointerPressRaycast (RaycastResult):指针按下时(OnPointerDown)射线检测到的结果。即使指针移开,该值仍保留,用于判断拖拽是否仍在有效范围内。 -
pointerEnter (GameObject):当前指针悬停在其上的 GameObject(即接收了OnPointerEnter的对象)。 -
pointerPress (GameObject):接收了OnPointerDown事件的 GameObject。 -
pointerDrag (GameObject):当前正在接收OnDrag事件的 GameObject。 -
hovered (List<GameObject>):指针当前悬停的所有对象的列表(按层级排序)。 -
rawPointerPress (GameObject):最初被按下的对象,即使它没有实现IPointerDownHandler接口。
状态标志
-
dragging (bool):指示当前是否正在进行拖拽操作。 -
useDragThreshold (bool):指示是否应应用拖动阈值(即移动超过一定像素才算拖拽)。 -
eligibleForClick (bool):指示当前指针状态是否符合触发点击事件的条件(例如,没有发生大幅度的拖拽)。
3. 常用方法
-
IsPointerMoving():返回布尔值,指示指针在当前帧是否有移动(基于delta的大小)。 -
IsScrolling():返回布尔值,指示是否有滚动输入。 -
Use():标记该事件已被使用。如果事件被标记为已使用,后续的 UI 元素将不再响应此事件(用于事件冒泡拦截)。 -
Reset():重置事件数据到初始状态,通常由事件系统内部调用以复用对象池。
4. 代码使用示例
示例 1:获取点击位置和按钮类型
1 using UnityEngine; 2 using UnityEngine.EventSystems; 3 4 public class ClickInfo : MonoBehaviour, IPointerClickHandler 5 { 6 public void OnPointerClick(PointerEventData eventData) 7 { 8 Debug.Log($"点击位置: {eventData.position}"); 9 Debug.Log($"点击按钮: {eventData.button}"); 10 Debug.Log($"点击次数: {eventData.clickCount}"); 11 12 // 判断是否是左键双击 13 if (eventData.button == PointerEventData.InputButton.Left && eventData.clickCount == 2) 14 { 15 Debug.Log("左键双击!"); 16 } 17 } 18 }
示例 2:实现拖拽功能
1 using UnityEngine; 2 using UnityEngine.EventSystems; 3 4 public class DraggableItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler 5 { 6 public void OnBeginDrag(PointerEventData eventData) 7 { 8 Debug.Log("开始拖拽"); 9 } 10 11 public void OnDrag(PointerEventData eventData) 12 { 13 // 使用 delta 移动物体,或者直接使用 position 设置新位置 14 // 这里演示将 UI 元素跟随鼠标移动 15 RectTransform rectTransform = GetComponent<RectTransform>(); 16 rectTransform.anchoredPosition += eventData.delta; 17 } 18 19 public void OnEndDrag(PointerEventData eventData) 20 { 21 Debug.Log("结束拖拽"); 22 } 23 }
示例 3:判断指针 ID(区分鼠标和触摸)
1 using UnityEngine; 2 using UnityEngine.EventSystems; 3 4 public class PointerIdentifier : MonoBehaviour, IPointerDownHandler 5 { 6 public void OnPointerDown(PointerEventData eventData) 7 { 8 int id = eventData.pointerId; 9 if (id < 0) 10 { 11 Debug.Log("鼠标操作: " + eventData.button); 12 } 13 else 14 { 15 Debug.Log("触摸操作, 触摸点ID: " + id); 16 } 17 } 18 }
5. 注意事项
- 依赖 EventSystem:
PointerEventData由EventSystem生成和管理。场景中必须存在EventSystem对象,且通常配合StandaloneInputModule或TouchInputModule使用。 - 射线检测要求:为了让 UI 元素接收
PointerEventData,它们必须位于 Canvas 下,并且通常需要有GraphicRaycaster(对于 UI)或PhysicsRaycaster(对于 3D 对象)。UI 元素本身通常需要是Graphic(如 Image, Text)或其子物体。 - 对象池复用:Unity 内部会对
PointerEventData进行对象池管理。不要在协程或异步操作中保存对该对象的引用,因为在下一次事件发生时,该对象的数据可能会被重置或覆盖。如果需要保存数据,应复制其值(如position、delta等)。 - 坐标系统:
position和pressPosition通常是屏幕空间坐标(像素),在使用时需注意与 UI 局部坐标或世界坐标的转换。
浙公网安备 33010602011771号