Unity–UI的Event事件
0.简介
UI作为交互的重要使者, 他需要不断的响应玩家的交互–按下,松开,点击,双击,长按等事件.
Unity中的UI事件系统是一个强大的框架,允许开发者创建交互式的用户界面。它基于事件驱动模型,意味着UI元素可以触发事件,而开发者可以编写代码来响应这些事件。UI事件系统特别适用于处理用户输入,如鼠标点击、触摸、拖拽等。
1.主要特点:
- 事件监听器:通过为UI元素添加事件监听器,可以捕获并响应特定的事件。
- 事件调度:Unity的事件系统负责事件的分发,确保正确的事件被发送到正确的监听器。
- 模块化:可以轻松地为不同的UI元素添加或移除事件监听器,从而创建动态和响应式的用户界面。
- 自定义事件:除了Unity内置的事件类型外,开发者还可以定义自己的事件类型。
2.常用UI事件:
- 点击(Click):当用户点击UI元素时触发。
- 双击(DoubleClick):当用户快速连续两次点击UI元素时触发。
- 按下(Down):当用户按下鼠标按钮或触摸屏幕时触发。
- 松开(Up):当用户释放鼠标按钮或停止触摸屏幕时触发。
- 进入(Enter):当指针(鼠标或触摸点)进入UI元素的边界时触发。
- 离开(Exit):当指针离开UI元素的边界时触发。
- 拖拽(Drag):当用户在UI元素上拖拽时触发。
3.使用UI事件:
- 添加UI组件:首先,在UI元素(如按钮、图像等)上添加相应的UI组件。
- 实现事件接口:在脚本中,实现相应的事件接口,如
IPointerClickHandler
。 - 添加事件监听器:在脚本中,为UI元素添加事件监听器。
- 处理事件:在接口方法中编写代码来处理事件。
4.具体步骤
1.命名空间
需要引入命名空间 UnityEngine.EventSystems
;
using UnityEngine.EventSystems;
2.自带的UI事件拆解
在Unity的UGUI中自带的一些组件中(例如: Image
, Button
)含有基本的UI响应事件, 例如Button的按下事件, 我们一般使用的通过OnClick
添加按下按钮的监听事件AddListener
, 即 button.OnClick.AddListener(响应函数名)
. 但是这是Unity为我们封装好的函数. 因此,如果想要自己实现自定义的交互事件,或者自己手动写一个Button脚本,就需要我们探索. 而Unity提供了基础的接口以便我们实现.
举一个简单的例子: 上文中,Unity中创建的Button我们可以通过添加OnClick.AddListener
的方式添加点击后的效果, 但是仔细思考一下. 鼠标的点击分为按下和松开. 因此我们自己写一个Button的点击事件,需要拆分为鼠标按下响应事件和鼠标松开响应事件. 如果你需要长按鼠标,3s,需要记录按下与松开之间的时间(该时间可以是秒数也可以是帧数)
3.鼠标按下帧检测
回到鼠标按下和松开例子中, 鼠标按下是后什么时候松开呢? 为了检测鼠标松开 ,计算机需要实时检测鼠标的按下状态, 这里的实时指的每一帧. 在每一帧中检测鼠标的状态,如果鼠标的状态发生改变,就调用对应的的函数. 为了检测鼠标的状态是否发生改变, 我们可以使用枚举类定义鼠标的各种状态, 例如: 按下--0, 松开--1, 按下并松开--3, 没有改变--4.
在Unity中以下是鼠标的按下状态检测枚举. 当然,VR中就是手柄的按下.
public enum FramePressState
{
Pressed = 0,
Released = 1,
PressedAndReleased = 2,
NotChanged = 3
}
4.常用接口
因此, 要自定一些效果,长按,短按, 滑动,双击,三击,需要我们自己实现. 或者使用现成的插件.
在Unity中常用的接口有:
鼠标进入, 鼠标移出, 鼠标按下, 鼠标抬起, 获得鼠标的的位置, 获取鼠标按下按键索引值(左键, 右键,中键)
对应的接口名称如下
IPointerEnterHandler
:当指针进入UI元素时触发。IPointerExitHandler
:当指针离开UI元素时触发。IPointerDownHandler
:当指针在UI元素上按下时触发。IPointerUpHandler
:当指针在UI元素上松开时触发。IPointerClickHandler
:当指针在UI元素上点击时触发。IPointerDoubleClickHandler
:当指针在UI元素上双击时触发。
5.实践代码
所以, 只要继承了接口,我们就可以实现自己想要的功能. 例如以下代码是实现了一张图片简单模拟按钮的功能, 实现了基础的鼠标进入,鼠标移出,鼠标按下,鼠标松开的自定义功能,修改了图片的颜色
using UnityEngine.EventSystems;
public class UIEvent : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler
{
private Image imgButton; // 图片
private Color originalColor; // 图片的原始颜色
private Color hoverColor; // 鼠标进入的颜色
private Color pressColor; // 鼠标按下的颜色
private Color unpressColor; // 鼠标松开的颜色
void Start()
{
imgButton = this.transform.gameObject.GetComponent<Image>();
originalColor = imgButton.color;
hoverColor = new Color(0, 0, 127, 0.5f);
pressColor = new Color(255, 255, 255, 0.5f);
unpressColor = new Color(0, 0, 0, 0.5f);
}
// 鼠标进入的接口实现
public void OnPointerEnter(PointerEventData eventData)
{
Debug.Log("鼠标进入 " + "鼠标坐标: x=" + eventData.position.x + " y=" +eventData.position.y);
// 改变图片颜色
imgButton.color = hoverColor;
}
// 鼠标离开的接口实现
public void OnPointerExit(PointerEventData eventData)
{
Debug.Log("鼠标离开 " + "鼠标坐标: x=" + eventData.position.x + " y=" + eventData.position.y);
imgButton.color = originalColor;
}
// 鼠标抬起的接口实现
public void OnPointerUp(PointerEventData eventData)
{
Debug.Log("鼠标松开 松开按键为:" + eventData.pointerId);
imgButton.color = unpressColor;
}
// 鼠标按下的接口实现
public void OnPointerDown(PointerEventData eventData)
{
Debug.Log("鼠标按下 按下按键为:" + eventData.pointerId);
imgButton.color = pressColor;
}
}
6.PointerEventData
在上面的代码中, 我们发现每一个接口实现中都有一个参数eventData
, 该参数是一个PointerEventData
的类型, 根据名称我们能大致推断出, 该参数包含了鼠标/指针(这里的指针不是这程序中的指针)的相关数据. 通过查看代码,我们能够发现里面的有很多方法. 以下是所有的方法. 根据返回的类型不同,我们可以获得具体的信息.
#region 程序集 UnityEngine.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// 项目名\Library\ScriptAssemblies\UnityEngine.UI.dll
#endregion
using System;
using System.Collections.Generic;
namespace UnityEngine.EventSystems
{
public class PointerEventData : BaseEventData
{
public List<GameObject> hovered;
public PointerEventData(EventSystem eventSystem);
public bool dragging { get; set; } // 是否处于退拽中
public InputButton button { get; set; }
public float pressure { get; set; } // 按下的压力
public float tangentialPressure { get; set; } // 触摸屏的侧压力
public float altitudeAngle { get; set; } // 触摸屏与笔的角度--可以调整画笔的粗细或压力
public float azimuthAngle { get; set; } // 触摸笔的旋转角度
public float twist { get; set; }
public Vector2 tilt { get; set; }
public PenStatus penStatus { get; set; }
public Vector2 radius { get; set; }
public Vector2 radiusVariance { get; set; }
public bool fullyExited { get; set; } // 鼠标完全移出
public bool reentered { get; set; } // 鼠标重新进入
public Camera enterEventCamera { get; }
public Camera pressEventCamera { get; }
public GameObject pointerPress { get; set; }
public bool useDragThreshold { get; set; }
public Vector2 scrollDelta { get; set; }
public int clickCount { get; set; }
public float clickTime { get; set; }
public GameObject pointerEnter { get; set; }
public GameObject lastPress { get; }
public GameObject rawPointerPress { get; set; }
public GameObject pointerDrag { get; set; }
public GameObject pointerClick { get; set; }
public RaycastResult pointerPressRaycast { get; set; }
public RaycastResult pointerCurrentRaycast { get; set; }
public int pointerId { get; set; } // 说的鼠标点击的按键索引值
public Vector2 position { get; set; } // 鼠标当前的屏幕坐标
public Vector2 delta { get; set; }
public Vector2 pressPosition { get; set; } // 鼠标按下的坐标
[Obsolete("Use either pointerCurrentRaycast.worldPosition or pointerPressRaycast.worldPosition")]
public Vector3 worldPosition { get; set; }
[Obsolete("Use either pointerCurrentRaycast.worldNormal or pointerPressRaycast.worldNormal")]
public Vector3 worldNormal { get; set; }
public bool eligibleForClick { get; set; }
public bool IsPointerMoving();
public bool IsScrolling();
public override string ToString();
public enum InputButton
{
Left = 0,
Right = 1,
Middle = 2
}
public enum FramePressState
{
Pressed = 0,
Released = 1,
PressedAndReleased = 2,
NotChanged = 3
}
}
}