UI在指定区域内拖拽

作用

UI在指定区域内移动,不超出指定区域的边界。

要求UI比区域小。

思路

  1. 获取移动UI四个角的位置;将位置转换为相对于移动区域的位置;
    RectTransform.GetWorldCorners获取四个角的位置
    利用矩阵将点转换到相对于移动区域的位置
  2. 创建移动区域Bounds和移动对象Bounds,通过Bounds判断UI是否超出区域
    注意:UI的宽度或高度大于移动区域,拖拽效果不理想。

脚本

脚本挂载到可以触发IDragHandler, IBeginDragHandler, IEndDragHandler接口的对象上。

设置移动区域,移动内容。

csharp 复制代码
using UnityEngine;
using UnityEngine.EventSystems;

public class SimpleDrag : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler
{
    [Header("移动区域")]
    [SerializeField] RectTransform moveAreaRect;

    [Header("移动内容")]
    [SerializeField] RectTransform contentRect;

    Vector2 startLocalCursor;
    Vector2 contentStartPosition;
    bool isDrag = false;

    Bounds moveAreaBounds;
    Bounds contentBounds;

    public void OnBeginDrag(PointerEventData eventData)
    {
        if (eventData.button != PointerEventData.InputButton.Left)
            return;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(moveAreaRect,
        eventData.position, eventData.pressEventCamera,
        out startLocalCursor);
        contentStartPosition = contentRect.anchoredPosition;
        isDrag = true;
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (isDrag == false) return;

        if (eventData.button != PointerEventData.InputButton.Left)
            return;

        Vector2 localCursor;
        if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(moveAreaRect,
        eventData.position, eventData.pressEventCamera, out localCursor))
            return;
        //从拖拽开始到当前帧,鼠标在 viewRect 局部坐标系中的位移
        var pointerDelta = localCursor - startLocalCursor;
        //目标位置
        var position = contentStartPosition + pointerDelta;
        //位移量
        var delta = position - contentRect.anchoredPosition;

        //区域限制
        UpdateBounds();
        var offset = CalculateOffest(delta);
        contentRect.anchoredPosition = position + offset;
    }

    private readonly Vector3[] corners = new Vector3[4];
    private void UpdateBounds()
    {
        moveAreaBounds = new Bounds(moveAreaRect.rect.center, moveAreaRect.rect.size);
        var viewWorldToLocal = moveAreaRect.worldToLocalMatrix;
        contentRect.GetWorldCorners(corners);
        var min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
        var max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
        for (int i = 0; i < corners.Length; i++)
        {
            var v = viewWorldToLocal.MultiplyPoint3x4(corners[i]);
            min = Vector3.Min(v, min);
            max = Vector3.Max(v, max);
        }
        contentBounds = new Bounds
        {
            min = min,
            max = max
        };
    }

    private Vector2 CalculateOffest(Vector2 delta)
    {
        Vector2 offset = Vector2.zero;

        Vector2 minMoveAreaValue = moveAreaBounds.min;
        Vector2 maxMoveAreaValue = moveAreaBounds.max;

        Vector2 minContentValue = contentBounds.min;
        Vector2 maxContentValue = contentBounds.max;

        minContentValue += delta;
        maxContentValue += delta;

        Vector2 minOffest = minMoveAreaValue - minContentValue;
        Vector2 maxOffest = maxMoveAreaValue - maxContentValue;

        if (minOffest.x > 0)
        {
            offset.x = minOffest.x;
        }
        if (maxOffest.x < 0)
        {
            offset.x = maxOffest.x;
        }
        if (minOffest.y > 0)
        {
            offset.y = minOffest.y;
        }
        if (maxOffest.y < 0)
        {
            offset.y = maxOffest.y;
        }
        return offset;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        if (eventData.button != PointerEventData.InputButton.Left)
            return;
        isDrag = false;
    }
}
相关推荐
RReality10 小时前
【Unity Shader URP】Matcap 材质捕捉实战教程
java·ui·unity·游戏引擎·图形渲染·材质
深蓝海拓10 小时前
基于QtPy (PySide6) 的PLC-HMI工程项目(十)框架初成的阶段总结
网络·笔记·python·学习·ui·plc
Swift社区10 小时前
鸿蒙游戏 UI 怎么设计才不乱?
游戏·ui·harmonyos
for_ever_love__15 小时前
UI 学习 Appearance 外观管理
学习·ui·ios·objective-c
RReality18 小时前
【Unity Shader URP】简易卡通着色(Simple Toon)实战教程
ui·unity·游戏引擎·图形渲染·材质
UXbot19 小时前
如何用 AI 快速生成完整的移动端 UI 界面:从描述到交付的实操教程
前端·ui·交互·ai编程·原型模式
ai_coder_ai19 小时前
自动化脚本ui编程之下拉列表框控件
ui·autojs·自动化脚本·冰狐智能辅助·easyclick
@Demi20 小时前
Cursor 配置 MasterGo MCP 还原UI设计稿
ui·cursor·mastergo·mcp
戴西软件21 小时前
戴西CAxWorks.VPG车辆工程仿真软件|假人+座椅双调整 汽车仿真效率直接拉满
java·开发语言·人工智能·python·算法·ui·汽车
瑞瑞小安21 小时前
Unity功能篇:文本框随文字内容动态调整
ui·unity