屏幕区域点击检测
此处直接代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Asstes.UI
{
/// <summary>
/// Introduction: 屏幕区域点击判断
/// Author:
/// Time:
/// </summary>
public class AreaClick
{
private static AreaClick m_instance;
public static AreaClick Instance
{
get
{
if (m_instance == null)
m_instance = new AreaClick();
return m_instance;
}
}
private int m_index;
private List<AreaRect> m_rects;
private List<AreaRect> m_removes;
private List<int> m_deletes;
public AreaClick()
{
m_index = 0;
m_rects = new List<AreaRect>();
m_removes = new List<AreaRect>();
m_deletes = new List<int>();
InputManager.Instance.AddListener(InputType.OnClick, OnClickScreen);
InputManager.Instance.AddListener(InputType.OnEndLongPress, OnClickScreen);
}
private void OnClickScreen(Vector2 param)
{
m_removes.Clear();
for (int i = 0; i < m_rects.Count; i++)//移除已删除的点
{
if(m_deletes.Contains(m_rects[i].id))
m_removes.Add(m_rects[i]);
}
for (int i = 0; i < m_removes.Count; i++)
{
m_rects.Remove(m_removes[i]);
}
m_deletes.Clear();
for (int i = 0; i < m_rects.Count; i++)
{
m_rects[i].OnClick(param);
}
}
/// <summary>
/// 添加检测
/// </summary>
/// <param name="area"></param>
/// <returns></returns>
public int AddCheck(AreaRect area)
{
area.id = m_index++;
m_rects.Add(area);
return area.id;
}
/// <summary>
/// 移除检测
/// </summary>
/// <param name="id"></param>
public void CancelCheck(int id)
{
if(!m_deletes.Contains(id))
m_deletes.Add(id);
}
}
public class AreaRect
{
private Rect m_rect;
private bool m_allNotice;
private bool m_onlyOnce;
private Callback_1<bool> m_callback;
internal int id;
/// <summary>
/// 是否只使用一次
/// </summary>
public bool UseOnce { get { return m_onlyOnce; } set { m_onlyOnce = value; } }
/// <summary>
/// 普通构造函数
/// </summary>
/// <param name="rect">在屏幕上的区域</param>
/// <param name="allNotice">通知点中和未点中</param>
/// <param name="callback">回调</param>
public AreaRect(Rect rect, bool allNotice, Callback_1<bool> callback)
{
m_rect = rect;
m_allNotice = allNotice;
m_callback = callback;
}
/// <summary>
/// 可缩放区域
/// </summary>
/// <param name="rect">设计时所选区域,如UI设计时的rect</param>
/// <param name="designSize">UI设计时屏幕分辨率</param>
/// <param name="allNotice">通知点中和未点中</param>
/// <param name="callback">回调</param>
public AreaRect(Rect rect, Vector2 designSize, bool allNotice, Callback_1<bool> callback)
{
float sx = Screen.width/designSize.x;
float sy = Screen.height/designSize.y;
Rect newRect = new Rect()
{
x = rect.x*sx,
y = rect.y*sy,
width = rect.width*sx,
height = rect.height*sy
};
m_rect = newRect;
m_allNotice = allNotice;
m_callback = callback;
}
/// <summary>
/// UI区域
/// </summary>
/// <param name="transform">RectTransform</param>
/// <param name="allNotice">通知点中和未点中</param>
/// <param name="callback">回调</param>
public AreaRect(Transform transform, bool allNotice, Callback_1<bool> callback)
{
RectTransform rectTransform = transform as RectTransform;
/*m_rect = rectTransform.rect; //没有考虑到缩放问题,当缩放后rect的长宽并未改变
m_rect.center = rectTransform.position;*/ //没有考虑到中心点影响,center并非world position
float w = rectTransform.sizeDelta.x * rectTransform.lossyScale.x;//消除缩放影响
float h = rectTransform.sizeDelta.y * rectTransform.localScale.y;
float x = rectTransform.position.x - rectTransform.pivot.x * w; //消除中心点并非pivot非(0.5,0.5)影响
float y = rectTransform.position.y - rectTransform.pivot.y * h;
m_rect.center = new Vector2(x, y);
m_rect.width = w;
m_rect.height = h;
m_allNotice = allNotice;
m_callback = callback;
}
/// <summary>
/// 是否在区域中
/// </summary>
/// <param name="pos"></param>
/// <returns></returns>
public bool IsContain(Vector3 pos)
{
return m_rect.Contains(pos);
}
public void OnClick(Vector2 pos)
{
if (IsContain(pos))
{
m_callback(true);
if(m_onlyOnce)
AreaClick.Instance.CancelCheck(id);
}
else if(m_allNotice)
{
m_callback(false);
}
}
}
}
其中InputManager是我自己实现的一个在多平台上判断点击事件的工具,
InputManager.Instance.AddListener(InputType.OnClick, OnClickScreen);
InputManager.Instance.AddListener(InputType.OnEndLongPress, OnClickScreen);
//可直接用
Input.GetMouseButtonDown(0) 和
Input.GetTouch(0)***************代替判断
一个很平常的需求、点击空白处关闭界面,以前自己的做法是给它做个全透明的图片托底(当时自己也没有想其他方法),当判断到点击是图片后关闭。但最近时遇到一个不能用这个方法的,因为你不能遮住其他的UI点击事件,故写了个工具,并做了个小扩展,目前只支持矩形区域的硬检测。目前可用到所有的屏幕区域检测和RectTransform检测。
由于最近用到在拖动时,如果在某个区域则相应拖动事件,如果超过这个区域则停止移动,于是改了一下代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Assets.UI
{
/// <summary>
/// Introduction: 屏幕区域点击移动判断
/// Author: Cheng
/// Time:
/// </summary>
public class AreaCheck
{
private static AreaCheck m_instance;
public static AreaCheck Instance
{
get
{
if (m_instance == null)
m_instance = new AreaCheck();
return m_instance;
}
}
private int m_index;
private List<AreaRect> m_rects;
private List<AreaRect> m_removes;
private List<int> m_deletes;
public AreaCheck()
{
m_index = 0;
m_rects = new List<AreaRect>();
m_removes = new List<AreaRect>();
m_deletes = new List<int>();
InputManager.Instance.AddListener(InputType.OnTouchBegin, OnTouchBegin);
InputManager.Instance.AddListener(InputType.OnMoveBegin, OnMoveBrgin);
InputManager.Instance.AddListener(InputType.OnMove, OnMove);
InputManager.Instance.AddListener(InputType.OnMoveEnd, OnMoveEnd);
InputManager.Instance.AddListener(InputType.OnClick, OnClickScreen);
InputManager.Instance.AddListener(InputType.OnEndLongPress, OnClickScreen);
}
private void OnTouchBegin(Vector2 param)
{
m_removes.Clear();
for (int i = 0; i < m_rects.Count; i++)//移除已删除的点
{
if (m_deletes.Contains(m_rects[i].id))
m_removes.Add(m_rects[i]);
}
for (int i = 0; i < m_removes.Count; i++)
{
m_rects.Remove(m_removes[i]);
}
m_deletes.Clear();
}
private void OnClickScreen(Vector2 param)
{
for (int i = 0; i < m_rects.Count; i++)
{
m_rects[i].OnClick(param);
}
}
private void OnMoveBrgin(Vector2 param)
{
for (int i = 0; i < m_rects.Count; i++)
{
m_rects[i].OnMoveBegin(param);
}
}
private void OnMove(Vector2 param)
{
for (int i = 0; i < m_rects.Count; i++)
{
m_rects[i].OnMove(param);
}
}
private void OnMoveEnd(Vector2 param)
{
for (int i = 0; i < m_rects.Count; i++)
{
m_rects[i].OnMoveEnd(param);
}
}
/**********因lua重载的callback只检测luafunction,改重载为重命名 T_T ************************/
public int AddClickCheckRect(Rect rect, bool noticeAll, Callback_1<bool> callback)
{
AreaRect area = new AreaRect(rect)
{
CheckClick = true,
ClickAllNotice = noticeAll,
ClickCallback = callback
};
return AddCheck(area);
}
public int AddClickCheckResizeRect(Rect rect, Vector2 designSize, bool noticeAll, Callback_1<bool> callback)
{
AreaRect area = new AreaRect(rect, designSize)
{
CheckClick = true,
ClickAllNotice = noticeAll,
ClickCallback = callback
};
return AddCheck(area);
}
public int AddClickCheckTransform(Transform transform, bool noticeAll, Callback_1<bool> callback)
{
AreaRect area = new AreaRect(transform)
{
CheckClick = true,
ClickAllNotice = noticeAll,
ClickCallback = callback
};
return AddCheck(area);
}
public int AddMoveCheckRect(Rect rect, bool outOnEnd, Callback_1<Vector2> begin, Callback_1<Vector2> move, Callback_1<Vector2> end)
{
AreaRect area = new AreaRect(rect)
{
CheckMove = true,
EndOnOut = outOnEnd,
MoveBeginCallback = begin,
MoveCallback = move,
MoveEndCallback = end
};
return AddCheck(area);
}
public int AddMoveCheckResizeRect(Rect rect, Vector2 designSize, bool outOnEnd, Callback_1<Vector2> begin, Callback_1<Vector2> move, Callback_1<Vector2> end)
{
AreaRect area = new AreaRect(rect, designSize)
{
CheckMove = true,
EndOnOut = outOnEnd,
MoveBeginCallback = begin,
MoveCallback = move,
MoveEndCallback = end
};
return AddCheck(area);
}
public int AddMoveCheckTransform(Transform transform, bool outOnEnd, Callback_1<Vector2> begin, Callback_1<Vector2> move, Callback_1<Vector2> end)
{
AreaRect area = new AreaRect(transform)
{
CheckMove = true,
EndOnOut = outOnEnd,
MoveBeginCallback = begin,
MoveCallback = move,
MoveEndCallback = end
};
return AddCheck(area);
}
/// <summary>
/// 添加检测
/// </summary>
/// <param name="area"></param>
/// <returns></returns>
[LuaInterface.NoToLua]
public int AddCheck(AreaRect area)
{
area.id = m_index++;
m_rects.Add(area);
return area.id;
}
/// <summary>
/// 移除检测
/// </summary>
/// <param name="id"></param>
public void CancelCheck(int id)
{
if(!m_deletes.Contains(id))
m_deletes.Add(id);
}
}
public class AreaRect
{
private Rect m_rect;
private bool moving;
internal int id;
/// <summary>
/// 鼠标移动时移除即结束
/// </summary>
public bool EndOnOut{ get; set; }
/// <summary>
/// 通知点中和未点中
/// </summary>
public bool ClickAllNotice { get; set; }
/// <summary>
/// 检测点击
/// </summary>
public bool CheckClick { get; set; }
/// <summary>
/// 检测移动
/// </summary>
public bool CheckMove { get; set; }
/// <summary>
/// 点击回调
/// </summary>
public Callback_1<bool> ClickCallback;
/// <summary>
/// 移动结束回调
/// </summary>
public Callback_1<Vector2> MoveBeginCallback;
/// <summary>
/// 移动回调
/// </summary>
public Callback_1<Vector2> MoveCallback;
/// <summary>
/// 移动结束回调
/// </summary>
public Callback_1<Vector2> MoveEndCallback;
/// <summary>
/// 普通构造函数
/// </summary>
/// <param name="rect">在屏幕上的区域</param>
public AreaRect(Rect rect)
{
m_rect = rect;
}
/// <summary>
/// 可缩放区域
/// </summary>
/// <param name="rect">设计时所选区域,如UI设计时的rect</param>
/// <param name="designSize">UI设计时屏幕分辨率</param>
public AreaRect(Rect rect, Vector2 designSize)
{
float sx = Screen.width/designSize.x;
float sy = Screen.height/designSize.y;
Rect newRect = new Rect()
{
x = rect.x*sx,
y = rect.y*sy,
width = rect.width*sx,
height = rect.height*sy
};
m_rect = newRect;
}
/// <summary>
/// UI区域
/// </summary>
/// <param name="transform">RectTransform</param>
public AreaRect(Transform transform)
{
RectTransform rectTransform = transform as RectTransform;
/*m_rect = rectTransform.rect; //没有考虑到缩放问题,当缩放后rect的长宽并未改变
m_rect.center = rectTransform.position;*/ //没有考虑到中心点影响,center并非world position
float w = rectTransform.sizeDelta.x * rectTransform.lossyScale.x;//消除缩放影响
float h = rectTransform.sizeDelta.y * rectTransform.localScale.y;
float x = rectTransform.position.x - rectTransform.pivot.x * w; //消除中心点并非pivot非(0.5,0.5)影响
float y = rectTransform.position.y - rectTransform.pivot.y * h;
m_rect.center = new Vector2(x, y);
m_rect.width = w;
m_rect.height = h;
}
/// <summary>
/// 是否在区域中
/// </summary>
/// <param name="pos"></param>
/// <returns></returns>
public bool IsContain(Vector3 pos)
{
return m_rect.Contains(pos);
}
/// <summary>
/// 区域点击检测
/// </summary>
/// <param name="pos"></param>
public void OnClick(Vector2 pos)
{
if(!CheckClick) return;
if (IsContain(pos) && ClickCallback != null)
{
ClickCallback(true);
}
else if (ClickAllNotice && ClickCallback != null)
{
ClickCallback(false);
}
}
/// <summary>
/// 开始移动
/// </summary>
/// <param name="pos"></param>
public void OnMoveBegin(Vector2 pos)
{
if (!CheckMove) return;
if (IsContain(pos))
{
moving = true;
if (MoveBeginCallback != null)
MoveBeginCallback(pos);
}
}
/// <summary>
/// 区域移动检测
/// </summary>
/// <param name="pos"></param>
public void OnMove(Vector2 pos)
{
if(!moving || !CheckMove) return;
if (IsContain(pos))
{
if (MoveCallback != null)
MoveCallback(pos);
}
else
{
if (EndOnOut)
{
moving = false;
if (MoveEndCallback != null)
MoveEndCallback(pos);
}
else
{
if (MoveCallback != null)
MoveCallback(pos);
}
}
}
/// <summary>
/// 移动结束
/// </summary>
/// <param name="pos"></param>
public void OnMoveEnd(Vector2 pos)
{
if (!moving || !CheckMove) return;
if (MoveEndCallback != null)
MoveEndCallback(pos);
}
}
}
使用方式现在直接调用AreaCheck的单例即可。