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;
}
}
}
总结
通过以上这些设置已经能够对图片的拖拽方向和拖拽缩放功能有了一个基本的设置,下面我们对拖拽时的整体变化做一些限制,使之能够在单个方向上进行拖动。
五、最新更新
对单方向的缩放控制进行了完善