C#实现对UI元素的拖拽

目录

C#实现对UI元素的拖拽

实现思路

1)按下记录偏移

2)拖动更新位置

为什么要使用offset?

计算逻辑

代码实现

效果

Unity常用UI交互接口


本篇文章来分享一下对UI元素的拖拽实现。

C#实现对UI元素的拖拽

实现思路

1)按下记录偏移

鼠标按下时,记录"UI元素锚点" 与"鼠标点击点"的位置差(offset)

2)拖动更新位置

鼠标移动时,用"鼠标实时位置+偏移量" 更新UI位置,保证UI元素始终跟随鼠标的"抓取点"移动。

为什么要使用offset?

使用offset是为了让拖拽操作更自然(避免鼠标点击物体时,物体瞬间跳到鼠标位置)。

若不使用offset,直接把物体位置设为鼠标位置(rectTransform.position = mousePos):当点击物体非中心点(比如左上角)时,物体会瞬间 "瞬移" 到鼠标指针正下方,拖拽手感非常生硬。因为鼠标点击的位置(mousePos)和物体锚点位置(rectTransform.position)通常不在同一位置,直接赋值会导致物体跳位。

计算逻辑

rectTransform.position:物体的锚点位置(默认是物体中心点);

mousePos:鼠标点击时,在世界空间中的指针位置;

offset:两者的差值 = 物体锚点位置 - 鼠标点击位置。

假设物体锚点在屏幕上的位置是 (100, 200)(rectTransform.position);点击的是物体左上角,此时鼠标位置是 (80, 220)(mousePos);则offset = (100,200) - (80,220) = (20, -20)。此时offset代表:"鼠标点击点"相对于"物体锚点"的偏移量(即锚点在鼠标点击点的右侧20、下方20位置)。

注意offset只需在OnPointerDown(鼠标按下时)计算一次,之后拖拽过程中保持不变。因为它只需要记录按下瞬间的偏移关系,拖动时复用即可。如果在OnDrag中重复计算,反而会导致物体抖动。

简而言之,offset就是记住抓住物体的位置,让拖拽时物体跟着抓点走,而不是跳来跳去。

代码实现

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

public class Drag : MonoBehaviour, IDragHandler, IPointerDownHandler
{
    private RectTransform rectTransform;
    private Vector3 offset;

    private void Awake()
    {
        rectTransform = gameObject.GetComponent<RectTransform>();
    }
    public void OnDrag(PointerEventData eventData)
    {
        if (eventData.pointerPressRaycast.gameObject == gameObject)
        {
            if (RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTransform, eventData.position, eventData.pressEventCamera, out Vector3 mousePos))
            {
                rectTransform.position = mousePos + offset;
            }
        }
    }
    public void OnPointerDown(PointerEventData eventData)
    {
        RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTransform, eventData.position, eventData.pressEventCamera, out Vector3 mousePos);
        offset = rectTransform.position - mousePos;
    }
}

效果

Unity常用UI交互接口

|----------------------|--------------------------------------------|-----------------------------|----------------------|
| 接口名称 | 核心方法 | 触发时机 | 使用场景 |
| IPointerDownHandler | OnPointerDown(PointerEventData eventData) | 鼠标/触摸按下到UI元素时(触发一次) | 拖拽起始记录、长按检测起点、按钮按下反馈 |
| IPointerUpHandler | OnPointerUp(PointerEventData eventData) | 鼠标/触摸在UI元素上抬起时(移出元素后抬起不触发) | 拖拽结束判定、按钮抬起反馈 |
| IPointerClickHandler | OnPointerClick(PointerEventData eventData) | 按下 + 抬起都在同一UI元素上(完整点击,触发一次) | 普通按钮点击、UI元素选中 |
| IPointerEnterHandler | OnPointerEnter(PointerEventData eventData) | 鼠标/触摸移入UI元素时(触发一次) | 悬停提示显示、按钮高亮 |
| IPointerExitHandler | OnPointerExit(PointerEventData eventData) | 鼠标/触摸移出UI元素时(触发一次) | 悬停提示关闭、按钮高亮取消 |
| IDragHandler | OnDrag(PointerEventData eventData) | 拖拽过程中每帧触发(需先按下UI元素) | UI拖拽移动、滑动条拖动、背包物品拖拽 |
| IBeginDragHandler | OnBeginDrag(PointerEventData eventData) | 拖拽开始时(按下后首次移动,触发一次) | 记录拖拽初始位置、生成拖拽虚影 |
| IEndDragHandler | OnEndDrag(PointerEventData eventData) | 拖拽结束时(抬起鼠标/触摸,触发一次) | 判定拖拽落点、恢复原UI状态 |
| IScrollHandler | OnScroll(PointerEventData eventData) | 鼠标滚轮滚动或触摸滑动时(每帧触发) | 自定义滚动视图UI缩放、滚动文本框 |
| ISelectHandler | OnSelect(BaseEventData eventData) | UI元素被选中时(如键Tab切换) | 输入框选中高亮、菜单选项选中反馈 |
| IDeselectHandler | OnDeselect(BaseEventData eventData) | UI元素失去选中时(如切换到其他元素) | 输入框失去焦点保存内容、取消菜单选中状态 |
| ISubmitHandler | OnSubmit(BaseEventData eventData) | 选中UI元素后提交(如按 Enter 键) | 菜单确认、表单提交、按钮激活 |
| ICancelHandler | OnCancel(BaseEventData eventData) | 触发取消操作时(如按Esc键) | 关闭弹窗、取消输入、退出当前界面 |

好了,本次的分享到这里就结束啦,希望对你有所帮助~

相关推荐
lqwh53541 小时前
python控制修改comsol边界条件仿真方法
开发语言·python
m***92381 小时前
【MySQL】C# 连接MySQL
数据库·mysql·c#
似水এ᭄往昔1 小时前
【C++】--二叉搜索树
开发语言·数据结构·c++
大道戏1 小时前
互联网程序设计第12 讲 RMI 程序设计
java·开发语言·计算机网络
水木姚姚1 小时前
C++程序创建(VS Code)
开发语言·c++
jtymyxmz1 小时前
《Unity Shader》11.3.2 广告牌技术
unity·游戏引擎
666HZ6661 小时前
C语言——C++的引用
c语言·开发语言·c++
San30.1 小时前
深入 JavaScript 原型与面向对象:从对象字面量到类语法糖
开发语言·javascript·ecmascript
皖南大花猪1 小时前
Go 项目中使用 Casbin 实现 RBAC 权限管理完整教程
开发语言·后端·golang·rbac·casbin