UGUI中的事件系统是处理用户输入(如鼠标点击、拖拽、键盘输入等)的核心机制。

这个系统负责检测用户的输入,并将这些输入传递给相应的UI组件进行处理。

EventSystem组件

负责管理和分发用户输入事件(如鼠标点击、触摸、键盘输入等)。每个包含UI元素的场景都应该有一个 EventSystem 组件来确保这些UI元素能够正确地响应用户的交互

它的功能如下:

  • 事件分发:负责将用户的输入事件(如鼠标点击、触摸等)分发给相应的UI组件。它通过射线检测(Raycasting)来确定哪个UI组件被点击或触碰

  • 输入管理:它管理用户的输入,包括鼠标、触摸屏和键盘输入。EventSystem 可以跟踪当前的选中对象、按下对象等状态信息

  • 事件处理:处理各种类型的事件,如点击、拖动、滚动等。它通过调用UI组件上的相应接口方法来响应这些事件。

image-doqr.png

Standalone Input Module组件

专门用于处理桌面设备(如 Windows、MacOS 和 Linux)上的用户输入。

它支持鼠标、键盘和游戏手柄等多种输入设备,你可以轻松地实现用户与 UI 元素之间的交互。

它的功能如下:

  • 鼠标输入

  • 键盘输入

  • 游戏手柄输入

UI事件监听接口

Raycast Target参数

在UGUI中基本上每个UI组件都会拥有这个参数,勾选后,该 UI 元素会参与 Unity 的射线检测(Event System)。

注意的是:如果多个 UI 元素重叠,射线检测会被最上层的元素拦截,下层元素可能无法触发事件。

如果想要穿透UI,或者该UI不想要被射线检测,就可以取消勾选它。

性能优化:避免为不需要交互的 UI 元素(如背景图)启用此选项,减少不必要的射线检测计算。

PointerEventData中的参数

UI事件依赖于Graphic Raycaster组件。它必须绑定Canvas,表示这个Canvas下所有UI元素支持的事件。

如何获取当前鼠标向里穿透的射线检测结果?

通过PointerEventData类中的pointerCurrentRaycast属性,来表示当前指针位置下,通过射线检测命中的 UI 元素及其相关数据。它直接关联到交互事件的触发目标(如点击、悬停、拖拽等)

获得鼠标悬停的UI信息

using UnityEngine.EventSystems;

public class HoverDetection : MonoBehaviour, IPointerEnterHandler
{
    public void OnPointerEnter(PointerEventData eventData)
    {
        // 获取当前悬停的 UI 元素
        GameObject hoveredObject = eventData.pointerCurrentRaycast.gameObject;
        Debug.Log("悬停在: " + hoveredObject.name);
    }
}

检测点击位置是否有UI元素

public class CustomInteraction : MonoBehaviour, IPointerClickHandler
{
    public void OnPointerClick(PointerEventData eventData)
    {
        // 检查点击位置是否有 UI 元素
        if (eventData.pointerCurrentRaycast.gameObject != null)
        {
            Vector2 clickPosition = eventData.pointerCurrentRaycast.screenPosition;
            Debug.Log("点击位置: " + clickPosition);
        }
    }
}

UI相关事件

点击事件

using UnityEngine;
using UnityEngine.EventSystems;

public class ClickHandler : MonoBehaviour, IPointerClickHandler
{
    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("点击了: " + gameObject.name);

        // 判断左键、右键或中键点击
        if (eventData.button == PointerEventData.InputButton.Left)
            Debug.Log("左键点击");
        else if (eventData.button == PointerEventData.InputButton.Right)
            Debug.Log("右键点击");
    }
}

双击事件

using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections;

public class DoubleClickHandler : MonoBehaviour, IPointerClickHandler
{
    private float lastClickTime;
    private const float doubleClickThreshold = 0.3f; // 双击间隔阈值

    public void OnPointerClick(PointerEventData eventData)
    {
        if (Time.time - lastClickTime < doubleClickThreshold)
        {
            Debug.Log("双击: " + gameObject.name);
        }
        lastClickTime = Time.time;
    }
}

拖拽事件

using UnityEngine;
using UnityEngine.EventSystems;

public class DragHandler : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    private RectTransform rectTransform;
    private CanvasGroup canvasGroup;

    void Awake()
    {
        rectTransform = GetComponent<RectTransform>();
        canvasGroup = GetComponent<CanvasGroup>();
        if (canvasGroup == null)
            canvasGroup = gameObject.AddComponent<CanvasGroup>();
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        // 拖拽开始时,降低透明度并禁用射线检测
        canvasGroup.alpha = 0.6f;
        canvasGroup.blocksRaycasts = false;
    }

    public void OnDrag(PointerEventData eventData)
    {
        // 更新拖拽对象的位置(基于屏幕坐标)
        rectTransform.anchoredPosition += eventData.delta / GetComponentInParent<Canvas>().scaleFactor;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        // 恢复透明度和射线检测
        canvasGroup.alpha = 1f;
        canvasGroup.blocksRaycasts = true;

        // 检查是否拖拽到有效区域
        if (eventData.pointerCurrentRaycast.gameObject == null)
            Debug.Log("拖拽到无效区域");
    }
}

悬停提示

using UnityEngine;
using UnityEngine.EventSystems;

public class HoverTip : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
    [SerializeField] private GameObject tipPanel; // 提示面板

    public void OnPointerEnter(PointerEventData eventData)
    {
        tipPanel.SetActive(true); // 显示提示
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        tipPanel.SetActive(false); // 隐藏提示
    }
}

长按

using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections;

public class LongPressHandler : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
    private bool isPressed;
    private const float longPressDuration = 1f; // 长按判定时间

    public void OnPointerDown(PointerEventData eventData)
    {
        isPressed = true;
        StartCoroutine(CheckLongPress());
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        isPressed = false;
    }

    private IEnumerator CheckLongPress()
    {
        yield return new WaitForSeconds(longPressDuration);
        if (isPressed)
        {
            Debug.Log("长按触发: " + gameObject.name);
            // 执行长按操作(如弹出菜单)
        }
    }
}