Unity UGUI 效果 之 鼠标拖拽UI实现放大缩小,实时调整UI大小(上)

Unity UGUI 效果 之 鼠标拖拽UI实现放大缩小,实时调整UI大小


前言

项目中想自定义编辑一个图片进行编辑展示,涉及到需要放大缩小的功能,看了一些资料很多都是拖拽的时候整体的放大缩小,所以自己在方法思路上进行改进功能。


一、简单介绍

本节使用 UGUI 通过代码实现鼠标点击拖拽UI实现动态调整图片大小的功能,共上下两篇,方法不唯一,欢迎指正。


二、实现原理

1、OnPointerEnter进入图片时检测鼠标在图片的区域位置;
2、OnPointerDown鼠标按下时,关闭检测并设置为拖拽状态;
3、OnDrag拖拽时,根据鼠标的位置进行图片大小的设置;
4、OnPointerUp鼠标抬起时,关闭拖拽状态;
5、OnPointerExit鼠标离开图片时关闭掉所有的检测以及拖拽判断

通过鼠标进入图片后所处的橙色区域位置判断拖拽的方向
在这里插入图片描述


三、效果预览

在这里插入图片描述

四、实现步骤

1、UI设置

面板基本结构设置
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
对四周拖拽箭头的预设位置以及锚点设置
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


2、代码编辑

1、边缘判断

 /// <summary>
 /// 边缘判断协程
 /// </summary>
 /// <returns></returns>
 IEnumerator edgeJudge()
 {
     yield return new WaitForEndOfFrame();
     while (true)
     {
         //通过图片内部点的位置与四边的距离 判断上下左右
         RectTransformUtility.ScreenPointToLocalPointInRectangle(panelRectTransform,
             Input.mousePosition, null, 
             out v2PointEnter);
          
         //  Debug.Log("_pos:" + v2PointEnter);  
         ui_edge = GetCurrentEdge(v2PointEnter);
          
         SetActiveEdgeImage(false);

         switch (ui_edge)
         {
             case UI_Edge.None:
                 SetActiveEdgeImage(false);
                 break;
             case UI_Edge.Left:
                 Left_Image.gameObject.SetActive(true);
                 Left_Image.localPosition = new Vector3(Left_Image.localPosition.x, Mathf.Clamp(v2PointEnter.y, -panelRectTransform.rect.height / 2, panelRectTransform.rect.height / 2),
                     Left_Image.localPosition.z);
                 break;
             case UI_Edge.Right:
                 Right_Image.gameObject.SetActive(true);
                 Right_Image.localPosition = new Vector3(Right_Image.localPosition.x, Mathf.Clamp(v2PointEnter.y, -panelRectTransform.rect.height / 2, panelRectTransform.rect.height / 2),
                     Right_Image.localPosition.z);
                 break;
             case UI_Edge.Down:
                 Down_Image.gameObject.SetActive(true);
                 Down_Image.localPosition = new Vector3(Mathf.Clamp(v2PointEnter.x, -panelRectTransform.rect.width / 2, panelRectTransform.rect.width / 2),
                     Down_Image.localPosition.y, Down_Image.localPosition.z);

                 break;
             case UI_Edge.Top:
                 Top_Image.gameObject.SetActive(true); 
                 Top_Image.localPosition = new Vector3(Mathf.Clamp(v2PointEnter.x, -panelRectTransform.rect.width / 2, panelRectTransform.rect.width / 2),
                     Top_Image.localPosition.y, Top_Image.localPosition.z);

                 break;
             default:
                 SetActiveEdgeImage(false);
                 break;
         }
         yield return new WaitForEndOfFrame();
     }

 }

2、拖拽改变大小

  float x, y;
  /// <summary>
  /// 拖拽实现Resize
  /// </summary>
  /// <param name="data"></param>
  public void OnDrag(PointerEventData data)
  { 
      if (panelRectTransform == null || ui_edge == UI_Edge.None||!isPointerDown)
          return;
      switch (ui_edge)
      {
          case UI_Edge.None:
              break;
          case UI_Edge.Top:
              x = panelRectTransform.sizeDelta.x;
              y = panelRectTransform.sizeDelta.y + data.delta.y;
              break;
          case UI_Edge.Down:
              x = panelRectTransform.sizeDelta.x;
              y = panelRectTransform.sizeDelta.y - data.delta.y;
              break;
          case UI_Edge.Left:
              x = panelRectTransform.sizeDelta.x - data.delta.x;
              y = panelRectTransform.sizeDelta.y;
              break;
          case UI_Edge.Right:
              x = panelRectTransform.sizeDelta.x + data.delta.x;
              y = panelRectTransform.sizeDelta.y;
              break;
          default:
              break;
      }
//直接进行赋值,这样会整体改变宽和高
     panelRectTransform.sizeDelta = new Vector2(Mathf.Clamp(x, minSize.x, maxSize.x), Mathf.Clamp(y, minSize.y, maxSize.y));

  }

3、完整代码

/*
 *FileName:      ResizePanel2.cs
 *Author:        SSW
 *Date:          2024/08/01 10:34:58
 *UnityVersion:  2020.3.40f1
 *Description:
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;

namespace SSWTools
{
    public enum UI_Edge
    {
        None,
        Top,
        Down,
        Left,
        Right,
        TopLeft,
        TopRight,
        BottomLeft,
        BottomRight
    }

    /// <summary>
    /// 拖动边缘,调整UI大小
    /// 使用说明
    /// 1、鼠标移动到UI的边缘,点击鼠标向内或向外拖动,实现调整UI大小
    /// 2、这里变化的 UI 的比例,你可以根据需要需改为 UI 宽高
    /// </summary>
    public class ResizePanel2 : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerEnterHandler, IPointerExitHandler, IPointerUpHandler
    {
        [Header("检测边距百分比")]
        [Range(0f,1f)]
        public float MonitorPercent=0.8f;
       
       
        /// <summary>
        /// 画布变化的大小限制值
        /// </summary>
       
        [Header("调整的最小值")]
        public Vector2 minSize = new Vector2(50, 50);
        [Header("调整的最大值")]
        public Vector2 maxSize = new Vector2(500, 500);

        [Header("边缘图片")]
        // 边缘图片
        public Transform Right_Image;
        public Transform Down_Image;
        public Transform Top_Image;
        public Transform Left_Image;

        // UI RectTransform
        private RectTransform panelRectTransform;

        // UI原始位置
        private Vector2 originalLocalPointerPosition;

        // UI原始大小
        private Vector2 originalSizeDelta;

        /// <summary>
        /// 鼠标刚进入时位置
        /// </summary>
        private Vector2 v2PointEnter;

        // 鼠标是否按下
        private bool isPointerDown = false;

        // 当前操作方向
        public UI_Edge ui_edge;

        public KeepFixed KeepFixed;
        void Awake()
        {
            KeepFixed = GetComponent<KeepFixed>();
            ui_edge = UI_Edge.None; 
             
            // 初始化
            panelRectTransform = transform.GetComponent<RectTransform>();

            // 隐藏边缘图标
            SetActiveEdgeImage(false);
        }

        private void Start()
        {

        }

        /// <summary>
        /// 鼠标在UI上按下的事件
        /// </summary>
        /// <param name="data"></param>
        public void OnPointerDown(PointerEventData data)
        {
          //  Debug.Log("OnPointerDown-----------"+ ui_edge.ToString());
            if (ui_edge==UI_Edge.None)
            {
                return;
            }
            // 鼠标按下
            isPointerDown = true;
            StopCoroutine("edgeJudge");
        }


        float x, y;
        /// <summary>
        /// 拖拽实现Resize
        /// </summary>
        /// <param name="data"></param>
        public void OnDrag(PointerEventData data)
        {
            if (panelRectTransform == null || ui_edge == UI_Edge.None || !isPointerDown)
                return;

            switch (ui_edge)
            {
                case UI_Edge.None:
                    break;
                case UI_Edge.Top:
                    x = panelRectTransform.sizeDelta.x;
                    y = panelRectTransform.sizeDelta.y + data.delta.y;
                    break;
                case UI_Edge.Down:
                    x = panelRectTransform.sizeDelta.x;
                    y = panelRectTransform.sizeDelta.y - data.delta.y;
                    break;
                case UI_Edge.Left:
                    x = panelRectTransform.sizeDelta.x - data.delta.x;
                    y = panelRectTransform.sizeDelta.y;
                    break;
                case UI_Edge.Right:
                    x = panelRectTransform.sizeDelta.x + data.delta.x;
                    y = panelRectTransform.sizeDelta.y;
                    break;
                default:
                    break;
            }
            //直接进行赋值,这样会整体改变宽和高
            panelRectTransform.sizeDelta = new Vector2(Mathf.Clamp(x, minSize.x, maxSize.x), Mathf.Clamp(y, minSize.y, maxSize.y));

        }


        /// <summary>
        /// 鼠标抬起事件
        /// </summary>
        /// <param name="eventData"></param>
        public void OnPointerUp(PointerEventData eventData)
        {
            // Debug.Log("OnPointerUp-----------"); 
            isPointerDown = false;
            ui_edge = UI_Edge.None;
              SetActiveEdgeImage(false);
             StopCoroutine("edgeJudge");
 
        }
        /// <summary>
        /// 鼠标进入UI的事件
        /// </summary>
        /// <param name="eventData"></param>
        public void OnPointerEnter(PointerEventData eventData)
        {
            Debug.Log("OnPointerEnter-----------");
            //Debug.Log(" eventData.position:" + eventData.position);
            if (isPointerDown)
            {
                return;
            }
            // 开启边缘检测
            StartCoroutine("edgeJudge");
 
        }

        /// <summary>
        /// 鼠标退出UI的事件
        /// </summary>
        /// <param name="eventData"></param>
        public void OnPointerExit(PointerEventData eventData)
        {
            if (isPointerDown)
            {
                return;
            }
            Debug.Log("OnPointerExit-----------"); 
            isPointerDown=false;
            StopCoroutine("edgeJudge"); 
            SetActiveEdgeImage(false);
         
        }


       

        /// <summary>
        /// 设置边缘画的显隐
        /// </summary>
        /// <param name="isActive"></param>
        private void SetActiveEdgeImage(bool isActive)
        {
            Right_Image.gameObject.SetActive(isActive);
            Down_Image.gameObject.SetActive(isActive);
            Left_Image.gameObject.SetActive(isActive);
            Top_Image.gameObject.SetActive(isActive);
        }

       

        /// <summary>
        /// 边缘判断协程
        /// </summary>
        /// <returns></returns>
        IEnumerator edgeJudge()
        {
            yield return new WaitForEndOfFrame();
            while (true)
            {
              
                RectTransformUtility.ScreenPointToLocalPointInRectangle(panelRectTransform,
                    Input.mousePosition, null, 
                    out v2PointEnter);
                 
                //  Debug.Log("_pos:" + v2PointEnter);  
                ui_edge = GetCurrentEdge(v2PointEnter);
                 
                SetActiveEdgeImage(false);

                switch (ui_edge)
                {
                    case UI_Edge.None:
                        SetActiveEdgeImage(false);
                        break;
                    case UI_Edge.Left:
                        Left_Image.gameObject.SetActive(true);
                        Left_Image.localPosition = new Vector3(Left_Image.localPosition.x, Mathf.Clamp(v2PointEnter.y, -panelRectTransform.rect.height / 2, panelRectTransform.rect.height / 2),
                            Left_Image.localPosition.z);
                        break;
                    case UI_Edge.Right:
                        Right_Image.gameObject.SetActive(true);
                        Right_Image.localPosition = new Vector3(Right_Image.localPosition.x, Mathf.Clamp(v2PointEnter.y, -panelRectTransform.rect.height / 2, panelRectTransform.rect.height / 2),
                            Right_Image.localPosition.z);
                        break;
                    case UI_Edge.Down:
                        Down_Image.gameObject.SetActive(true);
                        Down_Image.localPosition = new Vector3(Mathf.Clamp(v2PointEnter.x, -panelRectTransform.rect.width / 2, panelRectTransform.rect.width / 2),
                            Down_Image.localPosition.y, Down_Image.localPosition.z);

                        break;
                    case UI_Edge.Top:
                        Top_Image.gameObject.SetActive(true); 
                        Top_Image.localPosition = new Vector3(Mathf.Clamp(v2PointEnter.x, -panelRectTransform.rect.width / 2, panelRectTransform.rect.width / 2),
                            Top_Image.localPosition.y, Top_Image.localPosition.z);

                        break;
                    default:
                        SetActiveEdgeImage(false);
                        break;
                }
                yield return new WaitForEndOfFrame();
            }

        }

        /// <summary>
        /// 判断鼠标在 Panel 的那个边缘
        /// </summary>
        /// <param name="pos"></param>
        /// <returns></returns>
        private UI_Edge GetCurrentEdge(Vector2 pos)
        {

            if (pos.x < 0 && pos.x < -panelRectTransform.sizeDelta.x / 2 * MonitorPercent)
            {
                return UI_Edge.Left;
            }

            else if (pos.x > 0 && pos.x > panelRectTransform.sizeDelta.x / 2 * MonitorPercent)
            {
                return UI_Edge.Right;
            }
            else
            {
                if (pos.y < 0 && pos.y < -panelRectTransform.sizeDelta.y / 2 * MonitorPercent)
                {

                    return UI_Edge.Down;

                }
                else if (pos.y > 0 && pos.y > panelRectTransform.sizeDelta.y / 2 * MonitorPercent)
                {
                    return UI_Edge.Top;
                }
            }
            return UI_Edge.None;
        }

        private void SetWidthHeight(UI_Edge tuI_Edge,Vector2 wh) 
        {
            Vector2 V2Pos = panelRectTransform.anchoredPosition;
            Vector2 V2Size = panelRectTransform.sizeDelta;

        }
    }
}



总结

通过以上这些设置已经能够对图片的拖拽方向和拖拽缩放功能有了一个基本的设置,下面我们对拖拽时的整体变化做一些限制,使之能够在单个方向上进行拖动。

五、最新更新

对单方向的缩放控制进行了完善

Unity UGUI 效果 之 鼠标拖拽UI实现放大缩小,实时调整UI大小(下)

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity中,UGUI的EventTrigger是一个非常有用的组件,它可以用于实现UI拖拽和位置交换的功能。 首先,需要在要实现拖拽和位置交换的UI元素上添加EventTrigger组件。可以通过代码或者在Inspector面板中进行操作。然后,需要添加相应的事件触发器,例如拖拽开始、拖拽移动、拖拽结束等事件。 接下来,需要编写拖拽的逻辑代码。可以使用Unity提供的接口来处理拖拽事件,例如OnBeginDrag、OnDrag和OnEndDrag。在OnBeginDrag事件中,可以获取到拖拽起始位置,并将拖拽中的UI元素设置为可拖拽状态。在OnDrag事件中,可以实时获取到拖拽的位置,并将UI元素跟随鼠标或手指移动。在OnEndDrag事件中,可以获取到拖拽结束位置,并将UI元素设置回初始位置。 要实现位置交换功能,可以在UI元素上添加Collider组件,并根据拖拽的起始和结束位置来计算是否需要进行位置交换。可以使用RaycastHit来判断拖拽位置是否与其他UI元素重合,并记录下交换元素的信息。然后,根据交换元素的信息,可以将两个UI元素的位置进行互换。 最后,为了保证拖拽和位置交换功能的流畅性和用户体验,还可以添加一些动画效果和交互反馈。例如,在拖拽开始时可以添加一些拖拽阴影效果,使拖拽UI元素看起来更加立体和真实。在位置交换时,可以添加一些过渡动画,使UI元素的位置变换更加平滑和自然。 总之,利用Unity中UGUI的EventTrigger组件,结合适当的逻辑代码和交互反馈,可以很方便地实现UI拖拽和位置交换功能。这种功能可以在游戏开发中广泛应用,例如拼图游戏、物品交换系统等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值