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;
    }
}
相关推荐
青春易逝丶5 小时前
命令模式
命令模式
love530love5 小时前
冷门干货!llama.cpp 自带原生网页聊天 UI,无需第三方依赖一键开启
人工智能·windows·ui·llama·flash-attention·switch-cuda
漂移的电子2 天前
【常用】element-ui/moment.js/echarts.js等
javascript·ui·echarts
xy34532 天前
Axure 9.0 原生组件:让柱图实现动态交互(文本标签)
ui·交互·axure·原型·柱状图
我穿棉裤了2 天前
Element UI中el-upload文件上传失败会出发onRemove踩坑记录(已解决)
ui
不良人天码星2 天前
GUI自动化基础(一)
python·ui·自动化
_林枭_2 天前
ZW3D二次开发_UI_ZsCcTableWidget表格控件
qt·ui·zw3d
lierenvip2 天前
SpringDoc和Swagger使用
命令模式
东方不败之鸭梨的测试笔记3 天前
UI自动化执行时,元素不在视野内,需要拖动滑动条才能找到,这种元素怎么处理?
运维·ui·自动化