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;
    }
}
相关推荐
腾科IT教育13 小时前
HarmonyOS开发|ArkTS UI颜色API通用规则
ui·华为·harmonyos·harmonyos开发·鸿蒙应用开发工程师
小小工匠20 小时前
把生成模型接进 Agent:Higgsfield MCP 的架构拆解与工程实践
ui·higgsfield mcp·impeccable
czhaii21 小时前
word插入表格排版创建或编辑应用技巧
ui·c#·xhtml
淼澄研学2 天前
OpenAI集成Photoshop API:函数调用机制解析与实操指南
ui·photoshop
学习使我健康2 天前
一个基于 **Jetpack Compose + Material 3** 的 Android 入门示例项目,演示 Compose 声明式 UI 的核心用法
ui·kotlin·android jetpack
一夜白头催人泪2 天前
从0到1搭建AI驱动的UI自动化:无代码DOM设计文档
人工智能·ui·自动化
星辰即远方2 天前
计算器仿写总结
学习·ui·ios·cocoa·xcode
天天进步20153 天前
UI-TARS 源码解析 #21:从 UI-TARS 到本地桌面自动化:如何接入截图、模型推理和动作执行?
运维·ui·自动化
飞凌嵌入式3 天前
告别多端重复开发:Buildroot+Flutter实现全平台UI风格统一
flutter·ui