UGUI 实现拖拽功能

2021-03-10 10:32发布

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


示例简述:


在这里插入图片描述

上面的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;   //回复图片

    //}

}




————————————————

版权声明:本文为CSDN博主「妳是我改卟了的bug」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/Czhenya/article/details/82818881