版权声明:快乐源于分享,转载请附链接,,, https://blog.csdn.net/Czhenya/article/details/82818881
Unity 使用UGUI 实现图片的拖拽功能
先说下思路:开始点击 --> 跟随鼠标 --> 抬起鼠标(释放点击) ===》 这个一系列的操作之后,我们希望我们的图片也是跟着在动的,,,所以这就需要几个Unity 带个几个接口,,我这之前发布的长按和点击的同步文章也说过,这里就不在赘述,需要的同学可以到官网查看,或者看我之前发布的博文。链接:https://blog.csdn.net/Czhenya/article/details/82762637
在这个功能中我用的了这几个接口的方法:
- PointerEnterHandler - OnPointerEnter - 指针进入事件
- IBeginDragHandler - OnBeginDrag - 开始拖拽事件
- IDragHandler - OnDrag - 拖拽中事件
- IEndDragHandler - OnEndDrag - 拖拽结束(被拖拽的物体调用)
有了这几个事件后,还有一个Canvas Group组件,这个组件可以通过
this.GetComponent<CanvasGroup>().blocksRaycasts = false;//设置射线穿透
帮助你判断鼠标点击的是哪个物体,鼠标拖拽结束时碰到了那个物体,,,(PS:记得所有需要通过拖拽更换位置的都要添加这个组件) 如下图:
示例简述:
上面的1-6是我要移动的图片,,,就像我们手机上的图标换位置一样,(例1:点击5开始,到2结束 ,那么2-4的图标都向后移动一位,,5占据2的位置。例2:点击1开始,到4结束,那么2-4的图标都先前移动一位,1占据4的位置。诸如此类)
下面是我项目中解决这个问题的部分代码:
(PS:大家只看实现接口这几个方法就可以了,,,具体的逻辑还需要根据自己的项目需求实现)
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;
using DG.Tweening;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
[RequireComponent(typeof(RectTransform))]
////给控件添加监听事件要实现的一些接口
public class LobbyIconDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IDropHandler, IEndDragHandler, IPointerDownHandler
{
private Dictionary<int, Vector3> IconPosDict = new Dictionary<int, Vector3>();
public Dictionary<int, string> IconObjDict = new Dictionary<int, string>();
private string startName = ""; //从start开始 到 endName
private string endName = "";
private Vector3 BeforePos;
void Start()
{
//不变的位置字典...
IconPosDict.Add(1, new Vector3(-112, 105));
IconPosDict.Add(2, new Vector3(124, 105));
IconPosDict.Add(3, new Vector3(369, 105));
IconPosDict.Add(4, new Vector3(-112, -133));
IconPosDict.Add(5, new Vector3(124, -133));
IconPosDict.Add(6, new Vector3(369, -133));
//测试用的初始化...
IconObjDict.Add(1, "C#");
IconObjDict.Add(2, "Java");
IconObjDict.Add(3, "Lua");
IconObjDict.Add(4, "Unity");
IconObjDict.Add(5, "DW");
IconObjDict.Add(6, "PS");
}
//指针进入是调用 --> 用于记住开始点击的图片是谁,以及他现在的位置
public void OnPointerDown(PointerEventData EventData)
{
//Debug.Log("1 ... " + EventData.pointerEnter.name);
startName = EventData.pointerEnter.name;
for (int i = 0; i < IconObjDict.Count; i++)
{
if (EventData.pointerEnter.name == IconObjDict[i + 1])
{
BeforePos = IconPosDict[i + 1];
}
}
}
/// <summary>
/// 开始拖动
/// </summary>
/// <param name="EventData"></param>
public void OnBeginDrag(PointerEventData EventData)
{
this.GetComponent<CanvasGroup>().blocksRaycasts = false;//设置射线穿透
}
/// <summary>
/// 正在拖拽
/// </summary>
/// <param name="EventData"></param>
public void OnDrag(PointerEventData EventData)
{
this.transform.position = Input.mousePosition; //跟随鼠标的位置...
if (Mathf.Abs(Input.mousePosition.x) >= 600 || Mathf.Abs(Input.mousePosition.x) >= 300 )
{
//超出界限 就回到以前的位置...
this.transform.localPosition = BeforePos;
}
}
/// <summary>
/// 拖拽结束(被拖拽的物体调用)
/// </summary>
/// <param name="eventData"></param>
public void OnEndDrag(PointerEventData EventData)
{
endName = EventData.pointerEnter.name; //记录结束位置的图片名称,方便后面更改位置的逻辑操作
this.GetComponent<CanvasGroup>().blocksRaycasts = true;//设置射线穿透
// Debug.Log("3 ... " + EventData.pointerEnter.name);
ChangePos(); //调用图片移动的逻辑
}
/// <summary>
/// 拖拽结束(拖拽结束后的位置(即鼠标位置)如果有物体,则那个物体调用)
/// </summary>
/// <param name="EventData"></param>
public void OnDrop(PointerEventData EventData)
{
//很难用...
}
/// <summary>
/// 移动图标位置逻辑
/// </summary>
private void ChangePos()
{
int start = -1;
int end = -1;
for (int i = 0; i < IconObjDict.Count; i++)
{
if (startName == IconObjDict[i + 1])
{
start = i + 1;
}
if (endName == IconObjDict[i + 1])
{
end = i + 1;
}
}
// Debug.Log("start :" + start + " ... endNun:" + end);
if (start != -1 && end != -1) //判断是否发生移动...
{
//小 --> 大 (如: 1->6) 从Start后一位(2) 开始依次向前一位,直到 6 -> 5 结束 (2-1,3-2,4-3,5-4,6-5, 1-6)
if (start < end)
{
string tempName = IconObjDict[start];
for (int i = start; i < end; i++)
{
IconObjDict[i] = IconObjDict[i + 1];
}
IconObjDict[end] = tempName;
}
//大 --> 小 (如: 6->1) 从End(1) 开始依次向后一位,直到 Start(6) 结束 (1-2,2-3,3-4,4-5,5-6,6-1)
else if (start > end)
{
string tempName;
string temp = IconObjDict[start];
for (int i = start; i > end; i--)
{
IconObjDict[i] = IconObjDict[i - 1];
}
IconObjDict[end] = temp;
}
//else { 开始和结束一样,没有移动不做处理; }
for (int i = 0; i < IconObjDict.Count; i++)
{
Debug.Log("查看是否转换对了..." + IconObjDict[i + 1]);
}
}
else
{
Debug.Log("图标位置乱了...");
}
ReadIconPos();
}
/// <summary>
/// 对图标进行排列
/// </summary>
public void ReadIconPos()
{
isChangePos = true;
for (int i = 0; i < IconObjDict.Count; i++)
{
//DOTween.To(() => this.transform.GetChild(i).localPosition, r => this.transform.GetChild(i).localPosition = r, IconPosDict[i + 1], 0.2f);
GameObject go = FindPos(IconObjDict[i + 1]);
if (go != null)
{
DOTween.To(() => go.transform.localPosition, r => go.transform.localPosition = r, IconPosDict[i + 1], 0.2f);
}
//Debug.Log("排序后位置: " + LobbyIconDrag.Instance.IconObjDict[i + 1] + "... " + IconPosDict[i + 1]);
}
}
/// <summary>
/// 根据传入字符串,找到对应的图标
/// </summary>
/// <param name="str">图标名称</param>
/// <returns>图标对象</returns>
GameObject FindPos(string str)
{
GameObject go;
for (int i = 0; i < transform.parent.childCount; i++)
{
if (this.transform.parent.GetChild(i).name == str)
{
go = this.transform.parent.GetChild(i).gameObject;
return go;
}
}
return null;
}
//Vector3 imgReduceScale = new Vector3(0.8f, 0.8f, 1); //设置图片缩放
//Vector3 imgNormalScale = new Vector3(1, 1, 1); //正常大小
////当鼠标进入图片时调用 对应接口 IPointerEnterHandler
//public void OnPointerEnter(PointerEventData eventData)
//{
// this.transform.localScale = imgReduceScale; //缩小图片
//}
////当鼠标退出图片时调用 对应接口 IPointerExitHandler
//public void OnPointerExit(PointerEventData eventData)
//{
// this.transform.localScale = imgNormalScale; //回复图片
//}
}