最近开发项目中碰到的问题,需要实时监测鼠标是否进入、离开、点击UI区域,查了一些资料,总结了一些经验,写下这篇笔记,希望能够给碰到相同问题的同仁提供一些帮助
使用UGUI的GraphicRaycaster.Raycast方法进行检测鼠标位置,首先需要一个UI事件的管理类,代码如下:
使用事件字典每一个UI物体的同一种事件可以注册多个委托,只需要往MouseEventMgr中注册事件就行了:AddListener_…
当需要移除掉某一个事件时以RemoveListener_…即可
这个事件管理类随便挂在场景中的任意一个空物体即可
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class MouseEventMgr : MonoBehaviour
{
private GraphicRaycaster gra;
public delegate void EventUI(Transform target);
//鼠标点击UI事件字典
static Dictionary> mouseDownEvents = new Dictionary>();
//鼠标释放UI事件字典
static Dictionary> mouseUpEvents = new Dictionary>();
//鼠标进入UI事件字典
static Dictionary> mouseEnterEvents = new Dictionary>();
//鼠标离开UI事件字典
static Dictionary> mouseExitEvents = new Dictionary>();
//鼠标悬停UI事件字典
static Dictionary> mouseStayEvents = new Dictionary>();
private bool isCheck {
get {
return (mouseDownEvents.Count != 0 && mouseUpEvents.Count != 0 && mouseEnterEvents.Count != 0 && mouseExitEvents.Count != 0 && mouseStayEvents.Count != 0);
}
}
private void Awake()
{
gra = GameObject.Find("Canvas").GetComponent();
}
#region 事件管理
///
/// 给鼠标点击UI添加事件
///
/// 目标UI
/// 响应事件
public static void AddListener_MouseDown(Transform target,EventUI eventUI) {
if (mouseDownEvents.ContainsKey(target))
{
mouseDownEvents[target].Add(eventUI);
}
else {
List list = new List();
list.Add(eventUI);
mouseDownEvents.Add(target,list);
}
}
///
/// 给鼠标点击UI移除事件
///
/// 目标UI
/// 响应事件
public static void RemoveListener_MouseDown(Transform target, EventUI eventUI) {
if (mouseDownEvents.ContainsKey(target))
{
try
{
mouseDownEvents[target].Remove(eventUI);
if (mouseDownEvents[target].Count==0)
{
mouseDownEvents.Remove(target);
}
}
catch (System.Exception ex)
{
Debug.LogError("RemoveListener_MouseDown Error:"+ex.ToString());
}
}
}
///
/// 给鼠标释放UI添加事件
///
/// 目标UI
/// 响应事件
public static void AddListener_MouseUp(Transform target, EventUI eventUI)
{
if (mouseUpEvents.ContainsKey(target))
{
mouseUpEvents[target].Add(eventUI);
}
else
{
List list = new List();
list.Add(eventUI);
mouseUpEvents.Add(target, list);
}
}
///
/// 给鼠标释放UI移除事件
///
/// 目标UI
/// 响应事件
public static void RemoveListener_MouseUp(Transform target, EventUI eventUI)
{
if (mouseUpEvents.ContainsKey(target))
{
try
{
mouseUpEvents[target].Remove(eventUI);
if (mouseUpEvents[target].Count == 0)
{
mouseUpEvents.Remove(target);
}
}
catch (System.Exception ex)
{
Debug.LogError("RemoveListener_MouseUp Error:" + ex.ToString());
}
}
}
///
/// 给鼠标悬停UI添加事件
///
/// 目标UI
/// 响应事件
public static void AddListener_MouseStay(Transform target, EventUI eventUI)
{
if (mouseStayEvents.ContainsKey(target))
{
mouseStayEvents[target].Add(eventUI);
}
else
{
List list = new List();
list.Add(eventUI);
mouseStayEvents.Add(target, list);
}
}
///
/// 给鼠标悬停UI移除事件
///
/// 目标UI
/// 响应事件
public static void RemoveListener_MouseStay(Transform target, EventUI eventUI)
{
if (mouseStayEvents.ContainsKey(target))
{
try
{
mouseStayEvents[target].Remove(eventUI);
if (mouseStayEvents[target].Count == 0)
{
mouseStayEvents.Remove(target);
}
}
catch (System.Exception ex)
{
Debug.LogError("RemoveListener_MouseStay Error:" + ex.ToString());
}
}
}
///
/// 给鼠标进入UI添加事件
///
/// 目标UI
/// 响应事件
public static void AddListener_MouseEnter(Transform target, EventUI eventUI)
{
if (mouseEnterEvents.ContainsKey(target))
{
mouseEnterEvents[target].Add(eventUI);
}
else
{
List list = new List();
list.Add(eventUI);
mouseEnterEvents.Add(target, list);
}
}
///
/// 给鼠标进入UI移除事件
///
/// 目标UI
/// 响应事件
public static void RemoveListener_MouseEnter(Transform target, EventUI eventUI)
{
if (mouseEnterEvents.ContainsKey(target))
{
try
{
mouseEnterEvents[target].Remove(eventUI);
if (mouseEnterEvents[target].Count == 0)
{
mouseEnterEvents.Remove(target);
}
}
catch (System.Exception ex)
{
Debug.LogError("RemoveListener_MouseEnter Error:" + ex.ToString());
}
}
}
///
/// 给鼠标离开UI添加事件
///
/// 目标UI
/// 响应事件
public static void AddListener_MouseExit(Transform target, EventUI eventUI)
{
if (mouseExitEvents.ContainsKey(target))
{
mouseExitEvents[target].Add(eventUI);
}
else
{
List list = new List();
list.Add(eventUI);
mouseExitEvents.Add(target, list);
}
}
///
/// 给鼠标离开UI移除事件
///
/// 目标UI
/// 响应事件
public static void RemoveListener_MouseExit(Transform target, EventUI eventUI)
{
if (mouseExitEvents.ContainsKey(target))
{
try
{
mouseExitEvents[target].Remove(eventUI);
if (mouseExitEvents[target].Count == 0)
{
mouseExitEvents.Remove(target);
}
}
catch (System.Exception ex)
{
Debug.LogError("RemoveListener_MouseExit Error:" + ex.ToString());
}
}
}
#endregion
///
/// 触发目标事件
///
/// 目标类型
/// 事件管理字典
/// 目标
/// 事件参数
public void UseMouseEvent(Dictionary> dict,T key,Transform value) {
if (dict==null||!dict.ContainsKey(key))
{
return;
}
List events = dict[key];
for (int i = 0; i < events.Count; i++)
{
events[i]?.Invoke(value);
}
}
List lastList = null;
void Update()
{
if (!isCheck)
{
return;
}
PointerEventData pd = new PointerEventData(EventSystem.current);
pd.position = Input.mousePosition;
List list = new List();
gra.Raycast(pd, list);
if (mouseExitEvents.Count != 0 &&lastList!=null&&lastList.Count != 0)
{
CheckExit(list);
}
for (int i = 0; i < list.Count; i++)
{
Transform trans = list[i].gameObject.transform;
if (mouseEnterEvents.Count != 0)
{
if (!ListExist(lastList,list[i])&&mouseEnterEvents.ContainsKey(trans))
{
UseMouseEvent(mouseEnterEvents,trans,trans);
}
}
if (mouseStayEvents.ContainsKey(trans))
{
UseMouseEvent(mouseStayEvents,trans,trans);
}
if (Input.GetMouseButtonDown(0))
{
UseMouseEvent(mouseDownEvents, trans, trans);
}
else if (Input.GetMouseButtonUp(0))
{
UseMouseEvent(mouseUpEvents, trans, trans);
}
}
lastList = list;
}
//监测离开事件
void CheckExit(List curList) {
List exitList = GetExitObjs(curList);
for (int i = 0; i < exitList.Count; i++)
{
Transform exitObj = exitList[i].gameObject.transform;
if (mouseExitEvents.ContainsKey(exitObj))
{
UseMouseEvent(mouseExitEvents, exitObj, exitObj);
}
}
}
//得到所有鼠标离开的UI
List GetExitObjs(List curList) {
List exitList = new List();
for (int i = 0; i < lastList.Count; i++)
{
RaycastResult result = lastList[i];
if (!ListExist(curList,result))
{
exitList.Add(result);
}
}
return exitList;
}
//列表中是否包含指定元素
bool ListExist(List list, RaycastResult t) {
if (list==null||list.Count==0)
{
return false;
}
for (int i = 0; i < list.Count; i++)
{
if (list[i].gameObject==t.gameObject)
{
return true;
}
}
return false;
}
}
下面开始注册UI事件并处理事件逻辑,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIMgr : MonoBehaviour
{
public Transform[] mouseDownObjs;//需要处理鼠标点击的UI物体
public Transform[] mouseUpObjs;//需要处理鼠标释放的UI物体
public Transform[] mouseStayObjs;//需要处理鼠标悬停的UI物体
public Transform[] mouseExitObjs;//需要处理鼠标离开的UI物体
public Transform[] mouseEnterObjs;//需要处理鼠标进入的UI物体
void Start()
{
AddListener();
}
void AddListener() {
for (int i = 0; i < mouseDownObjs.Length; i++)
{
Transform obj = mouseDownObjs[i];
MouseEventMgr.AddListener_MouseDown(obj,MouseDown);
}
for (int i = 0; i < mouseUpObjs.Length; i++)
{
Transform obj = mouseUpObjs[i];
MouseEventMgr.AddListener_MouseUp(obj, MouseUp);
}
for (int i = 0; i < mouseStayObjs.Length; i++)
{
Transform obj = mouseStayObjs[i];
MouseEventMgr.AddListener_MouseStay(obj, MouseStay);
}
for (int i = 0; i < mouseExitObjs.Length; i++)
{
Transform obj = mouseExitObjs[i];
MouseEventMgr.AddListener_MouseExit(obj, MouseExit);
}
for (int i = 0; i < mouseEnterObjs.Length; i++)
{
Transform obj = mouseEnterObjs[i];
MouseEventMgr.AddListener_MouseEnter(obj, MouseEnter);
}
}
public void MouseDown(Transform obj)
{
Debug.Log("鼠标点击到UI物体:"+obj.name);
}
public void MouseUp(Transform obj)
{
Debug.Log("鼠标释放到UI物体:" + obj.name);
}
public void MouseStay(Transform obj)
{
Debug.Log("鼠标悬停到UI物体:" + obj.name);
}
public void MouseExit(Transform obj)
{
Debug.Log("鼠标离开UI物体:" + obj.name);
}
public void MouseEnter(Transform obj)
{
Debug.Log("鼠标进入UI物体:" + obj.name);
}
}