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;
    }
}
相关推荐
豆豆13 小时前
2026实测:AI生成UI设计稿后,如何优雅集成到PageAdmin CMS?(附标签替换代码)
人工智能·ui·cms·建站系统·ai工具·ai建站
爱吃大芒果14 小时前
鸿蒙 ArkUI 架构蓝图:MoodLite 的 UI 渲染与数据逻辑解耦实践
ui·架构·harmonyos
Ulyanov14 小时前
深入QML滑块与进度控制:构建动态数据可视化界面:QML+PySide6现代开发入门(六)
开发语言·python·算法·ui·信息可视化·雷达电子对抗仿真
爱吃大芒果15 小时前
声明式 UI 进阶剖析:复杂长列表懒加载与视图模型 (ViewModel) 的内存优化策略
ui·华为·harmonyos
ZC跨境爬虫15 小时前
跟着 MDN 学CSS day_42:等分轨道、层叠放置与混合布局
前端·javascript·css·ui·html
for_ever_love__1 天前
UI学习:UISearchController基础了解和应用
学习·ui·ios·objective-c
ZC跨境爬虫1 天前
跟着 MDN 学CSS day_39:(Flexbox 弹性盒子核心机制)
前端·css·ui·html·tensorflow
海兰1 天前
【文字三国志:第六篇】天命重构,UI组件设计细节
人工智能·ui·语言模型·小程序
EMTime1 天前
玲珑GUI-工程设置
单片机·mcu·ui·用户界面