注释很详细,不多做介绍了!
using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using UnityEngine.EventSystems;
/// <summary>
/// UGUI 之 界面拖动 以及 焦点界面
/// </summary>
public class UI_DragObject : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IPointerDownHandler, IDragHandler
{
private RectTransform m_Target; //获取拖拽对象,
private RectTransform m_CanvasRectTransform; //父对象,画布 canvas, canvas的大小刚好就是整个屏幕.
private Vector2 m_MouseStartPosition = Vector2.zero; //鼠标起点位置
private Vector2 m_TargetStartPosition = Vector2.zero; //面板起点位置
private bool m_Dragging = false; //拖拽状态的判断
private static int siblingIndex; //UI显示层级
void Awake()
{
//先获取对象
m_Target = transform.parent as RectTransform;
m_CanvasRectTransform = m_Target.parent as RectTransform;
siblingIndex = m_Target.transform.GetSiblingIndex(); //获取层级
}
/// <summary>
/// 保证当前UI 要显示在其他UI上面
/// </summary>
/// <param name="data"></param>
public void OnPointerDown(PointerEventData data)
{
siblingIndex++;
m_Target.transform.SetSiblingIndex(siblingIndex);
}
/// <summary>
/// 拖拽开始
/// </summary>
/// ScreenPointToLocalPointInRectangle(RectTransform rect, Vector2 screenPoint, Camera cam, out Vector2 localPoint); 方法
/// 屏幕空间点转换为矩形变换内部的本地位置,该点在它的矩形平面上。
/// <param name="data"></param>
public void OnBeginDrag(PointerEventData data)
{
//判空
if(m_Target == null)
{
Debug.Log("m_Target is null");
return;
}
//鼠标起点坐标
RectTransformUtility.ScreenPointToLocalPointInRectangle(this.m_CanvasRectTransform, data.position, data.pressEventCamera, out this.m_MouseStartPosition);
//面板起点坐标
this.m_TargetStartPosition = this.m_Target.anchoredPosition; //锚点坐标
//拖拽中
this.m_Dragging = true;
}
/// <summary>
/// 拖拽结束
/// </summary>
/// <param name="data"></param>
public void OnEndDrag(PointerEventData data)
{
//拖拽结束
this.m_Dragging = false;
}
/// <summary>
/// 拖拽中
/// </summary>
/// <param name="data"></param>
public void OnDrag(PointerEventData data)
{
if (m_Target == null || this.m_CanvasRectTransform == null)
{
Debug.Log(m_Target);
Debug.Log(m_CanvasRectTransform);
return;
}
//当前鼠标坐标转换
Vector2 mousePos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(this.m_CanvasRectTransform, data.position, data.pressEventCamera, out mousePos);
//是否在拖拽中
if (this.m_Dragging)
{
mousePos = this.ClampToCanvas(mousePos); //限制鼠标不得在画布外
}
// 移动位置 = 起点 + 鼠标当前位置 - 鼠标起点位置
Vector2 newPosition = this.m_TargetStartPosition + (mousePos - this.m_MouseStartPosition);
// 位置更改
this.m_Target.anchoredPosition = newPosition;
}
/// <summary>
/// 限制在画布内
/// </summary>
/// 这里使用了 GetLocalCorners( Vector3[] for conersArray) 方法 获取当前物体的 四个顶点 在 父物体坐标系 的坐标 顺序 从左下 -> 右下
/// 同理: GetWorldCorners( Vector3[] for conersArray) 方法 获取当前物体的 四个顶点 在 世界坐标系 的坐标 顺序 从左下 -> 右下
/// <param name="position"></param>
/// <returns></returns>
protected Vector2 ClampToCanvas(Vector2 position)
{
if (this.m_CanvasRectTransform != null)
{
//先创建数组存放四个顶点坐标
Vector3[] corners = new Vector3[4];
//获取顶点坐标
this.m_CanvasRectTransform.GetLocalCorners(corners);
//限制其坐标 X,Y 在 min.X / Y - max.X / Y 之间
float clampedX = Mathf.Clamp(position.x, corners[0].x, corners[2].x); // Clamp(Value,min,max) if (value > max) return max ; 反之
float clampedY = Mathf.Clamp(position.y, corners[3].y, corners[1].y);
//返回
return new Vector2(clampedX, clampedY);
}
return position;
}
}