Unity UGUI 拖拽组件
效果展示
使用方式
拖到图片上即可用
父节点会约束它的活动范围哦~
父节点会约束它的活动范围哦~
父节点会约束它的活动范围哦~
源码: 点击图片开始拖动 受到父节点区域影响
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;/// <summary>
/// UI DragComponent
///
/// Click on the image area to start dragging
/// The parent node scope was affected. Procedure
///
/// Easy~~~
///
/// @anchor ChenJC
/// @time: 2023/02/28
/// </summary>
public class DragComponent : MonoBehaviour, IBeginDragHandler, IDragHandler, IDropHandler
{RectTransform rectTransform, parentRectTrans;float minX, minY, maxX, maxY;Vector2 offset;public delegate void DragHandlerEvent( Vector2 currentPos );public DragHandlerEvent dragBeginEvent;public DragHandlerEvent dragEvent;public DragHandlerEvent dropEvent;#region Monobehavior Methodsprivate void Awake(){parentRectTrans = transform.parent as RectTransform;rectTransform = transform as RectTransform;}private void Start(){var parentAnchorX = parentRectTrans.pivot.x * parentRectTrans.rect.width;var parentAnchorY = parentRectTrans.pivot.y * parentRectTrans.rect.height;minX = rectTransform.rect.width * 0.5f - parentAnchorX;minY = rectTransform.rect.height * 0.5f - parentAnchorY;maxX = parentRectTrans.rect.width - rectTransform.rect.width * 0.5f - parentAnchorX;maxY = parentRectTrans.rect.height - rectTransform.rect.height * 0.5f - parentAnchorY;}#endregion#region Internal Methodsprivate Vector2 ConstraintWithinParentNode( Vector2 pos ){pos.x = Mathf.Clamp( pos.x, minX, maxX );pos.y = Mathf.Clamp( pos.y, minY, maxY );return pos;}private bool Convert2local( Vector2 screenPos, out Vector2 localPos, Camera camera ){return RectTransformUtility.ScreenPointToLocalPointInRectangle( parentRectTrans, screenPos, camera, out localPos );}#endregion#region Drag Handler Methodspublic void OnBeginDrag( PointerEventData eventData ){Vector2 localPos;if ( Convert2local( eventData.position, out localPos, eventData.pressEventCamera ) ){Vector2 src = rectTransform.localPosition;offset = src - localPos;dragBeginEvent?.Invoke( src );}}public void OnDrag( PointerEventData eventData ){Vector2 localPos;if ( Convert2local( eventData.position, out localPos, eventData.pressEventCamera ) ){Vector2 dest = ConstraintWithinParentNode( localPos + offset );rectTransform.localPosition = dest;dragEvent?.Invoke( dest );}}public void OnDrop( PointerEventData eventData ){Vector2 localPos;if ( Convert2local( eventData.position, out localPos, eventData.pressEventCamera ) ){Vector2 dest = ConstraintWithinParentNode( localPos + offset );dropEvent?.Invoke( dest );}}#endregion
}
拖拽事件监听
依次 开始拖拽时触发; 拖拽过程中持续触发; 拖拽结束时触发
原理介绍
开始拖拽的时候
offset = sub.localtionPos - p.localtionPos
通过计算鼠标点 计算出 相对于图片原点的 偏移 并缓存
public void OnBeginDrag( PointerEventData eventData ){Vector2 localPos;if ( Convert2local( eventData.position, out localPos, eventData.pressEventCamera ) ){Vector2 src = rectTransform.localPosition;offset = src - localPos;dragBeginEvent?.Invoke( src );}}
拖拽过程中 我们加上这个偏移向量 就能得到相对偏移的拖拽方式
sub.locationsPos = p.locationPos + offset
public void OnDrag( PointerEventData eventData ){Vector2 localPos;if ( Convert2local( eventData.position, out localPos, eventData.pressEventCamera ) ){Vector2 dest = ConstraintWithinParentNode( localPos + offset );rectTransform.localPosition = dest;dragEvent?.Invoke( dest );}}
限制活动范围 保持在父节点以内活动
示意图
如图可以知道 最小X 等于自身宽 的一半 同时要减去父节点 宽的一半
可以知道 最小Y 等于自身高 的一半 同时要减去父节点 高的一半
最大值 是父节点一半 - 自身大小的一半 在Unity里 你可以通过 pivot 来获取 图片锚点相对于图片自身size的百分比值 ( 0~1)
计算出最小X,最小Y,最大X,最大Y
private void Start(){var parentAnchorX = parentRectTrans.pivot.x * parentRectTrans.rect.width;var parentAnchorY = parentRectTrans.pivot.y * parentRectTrans.rect.height;minX = rectTransform.rect.width * 0.5f - parentAnchorX;minY = rectTransform.rect.height * 0.5f - parentAnchorY;maxX = parentRectTrans.rect.width - rectTransform.rect.width * 0.5f - parentAnchorX;maxY = parentRectTrans.rect.height - rectTransform.rect.height * 0.5f - parentAnchorY;}
新的位置约束在范围内
private Vector2 ConstraintWithinParentNode( Vector2 pos ){pos.x = Mathf.Clamp( pos.x, minX, maxX );pos.y = Mathf.Clamp( pos.y, minY, maxY );return pos;}
源码: 屏幕任意位置可拖动 受到父节点区域影响
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;/// <summary>
/// Unrestricted UI DragComponent
///
///
/// Drag the component anywhere.
/// The parent node scope was affected. Procedure
///
/// @anchor ChenJC
/// @time: 2023/03/01
/// </summary>
[RequireComponent( typeof( RectTransform ) )]
public class UnrestrictedDragComponent : MonoBehaviour
{public bool realtimeUpdatePosition = false, hasCaptureFingerDropPoint = false;protected RectTransform rectTransform, parentRectTrans;protected float minX, minY, maxX, maxY;private Vector2 ImageRelativeDragPosition;public delegate void DragHandlerEvent( Vector2 currentPos );public DragHandlerEvent beginDragEvent;public DragHandlerEvent dragEvent;public DragHandlerEvent endDragEvent;#region Monobehavior Methodsprivate void Awake(){parentRectTrans = transform.parent as RectTransform;rectTransform = transform as RectTransform;}private void OnTransformParentChanged(){parentRectTrans = transform.parent as RectTransform;}private void OnEnable() => hasCaptureFingerDropPoint = false;private void Update(){#if UNITY_EDITORif ( Input.anyKey ){if ( Input.GetMouseButtonDown( 0 ) ){hasCaptureFingerDropPoint = true;TouchBegin( Input.mousePosition );}if ( Input.GetMouseButton( 0 ) ){if ( !hasCaptureFingerDropPoint ){hasCaptureFingerDropPoint = true;TouchBegin( Input.mousePosition );return;}TouchMoveing( Input.mousePosition );}}if ( Input.GetMouseButtonUp( 0 ) ){TouchEnd( Input.mousePosition );}#elif UNITY_ANDROID || UNITY_IOSif ( Input.touchSupported && Input.touchCount > 0 ){var touch = Input.GetTouch( 0 );if ( touch.phase == TouchPhase.Began ){hasCaptureFingerDropPoint = true;TouchBegin( touch.position );}if ( touch.phase == TouchPhase.Moved || touch.phase == TouchPhase.Stationary ){if ( !hasCaptureFingerDropPoint ){hasCaptureFingerDropPoint = true;TouchBegin( Input.mousePosition );return;}TouchMoveing( touch.position );}if ( touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled ){TouchEnd( touch.position );}}
#endifif ( realtimeUpdatePosition ){rectTransform.localPosition = ConstraintWithinParentNode( rectTransform.localPosition );}}#endregion#region Internal Methods//实时计算包围盒protected virtual void RealtimeCalcBounds(){var rad = rectTransform.localEulerAngles.z * Mathf.Deg2Rad;var a = rectTransform.rect.height * ( 1.0f - rectTransform.pivot.y ) * Mathf.Cos( rad );var b = rectTransform.rect.height * rectTransform.pivot.y * Mathf.Sin( rad );var selfMinX = Mathf.Abs( Mathf.Min( a, b ) );var selfMaxX = Mathf.Abs( Mathf.Max( a, b ) );var c = rectTransform.rect.height * rectTransform.pivot.y * Mathf.Cos( rad );var d = rectTransform.rect.height * ( 1.0f - rectTransform.pivot.y ) * Mathf.Sin( rad );var selfMinY = Mathf.Abs( Mathf.Max( c, d ) );var selfMaxY = Mathf.Abs( Mathf.Min( c, d ) );var layoutOffsetX = ( rectTransform.pivot.x - parentRectTrans.anchorMin.x ) * rectTransform.rect.width;var layoutOffsetY = ( rectTransform.pivot.y - parentRectTrans.anchorMin.y ) * rectTransform.rect.height;minX = selfMinX + layoutOffsetX - parentRectTrans.pivot.x * parentRectTrans.rect.width;minY = selfMinY + layoutOffsetY - parentRectTrans.pivot.y * parentRectTrans.rect.height;maxX = parentRectTrans.rect.width * ( 1.0f - parentRectTrans.pivot.x ) - selfMaxX;maxY = parentRectTrans.rect.height * ( 1.0f - parentRectTrans.pivot.y ) - selfMaxY;}//约束在父节点以内private Vector2 ConstraintWithinParentNode( Vector2 pos ){RealtimeCalcBounds();pos.x = Mathf.Clamp( pos.x, minX, maxX );pos.y = Mathf.Clamp( pos.y, minY, maxY );return pos;}//如果你的相机 不是用 MainCamera 来渲染UI//请将这里的Camera调整成对应Canvas Cameraprivate bool Convert2local( Vector2 screenPos, out Vector2 localPos ){return RectTransformUtility.ScreenPointToLocalPointInRectangle( parentRectTrans, screenPos, Camera.main, out localPos );}/// <summary>/// 更新位置/// </summary>private void UpdatePosition( ref Vector2 pos ){if ( Convert2local( pos, out Vector2 localpos ) ){rectTransform.localPosition = ConstraintWithinParentNode( localpos + ImageRelativeDragPosition );}}#endregion#region Touch Handler Methods//开始点击的时候触发private void TouchBegin( Vector2 pos ){if ( Convert2local( pos, out Vector2 localpos ) ){Vector2 src = rectTransform.localPosition;ImageRelativeDragPosition = src - localpos;beginDragEvent?.Invoke( src );}}//拖拽的时候触发private void TouchMoveing( Vector2 pos ){UpdatePosition( ref pos );dragEvent?.Invoke( rectTransform.localPosition );}//抬起手指的时候触发private void TouchEnd( Vector2 pos ){UpdatePosition( ref pos );endDragEvent?.Invoke( rectTransform.localPosition );}#endregion}
Unity UGUI 拖拽组件相关推荐
- html 树形图可拖拽,HTML5拖拽API实现vue树形拖拽组件
因业务场景需要一个可拖拽修改节点位置的树形组件,因此动手撸了一个,乘此机会摸了一把html5原生拖拽.近期有时间将核心部分代码抽出,简单说下实现方式. 1.树形结构-组件递归使用 树形结构非常简单,t ...
- vue-slicksort拖拽组件
vue-slicksort拖拽组件 安装 通过npm安装 $ npm install vue-slicksort --save 通过yarn安装 $ yarn add vue-slicksort ...
- 微信小程序图片上传九宫格拖拽组件
微信小程序图片上传&九宫格拖拽组件 前言 图片上传加九宫格拖拽是一个比较常用的组件,常用于发帖或者评论等内容上传模块,我这篇九宫格拖拽的思路是借鉴了一款优雅的小程序拖拽排序组件实现这篇文章 实 ...
- 可视化拖拽组件库一些技术要点原理分析(三)
本文是可视化拖拽系列的第三篇,之前的两篇文章一共对 17 个功能点的技术原理进行了分析: 编辑器 自定义组件 拖拽 删除组件.调整图层层级 放大缩小 撤消.重做 组件属性设置 吸附 预览.保存代码 绑 ...
- Vue 实现拖拽模块(二)自定义拖拽组件位置
上文介绍了 拖拽添加组件 的简单实现,本文将继续给大家分享如何自定义拖拽组件位置的简单实现,文中通过示例代码介绍,感兴趣的小伙伴们可以了解一下 本文主要介绍了 Vue自定义拖拽组件位置的简单实现,具体 ...
- 可视化拖拽组件库一些技术要点原理分析(二)
本文是对<可视化拖拽组件库一些技术要点原理分析>[1]的补充.上一篇文章主要讲解了以下几个功能点: 1.编辑器2.自定义组件3.拖拽4.删除组件.调整图层层级5.放大缩小6.撤消.重做7. ...
- react拖拉流程图_react 拖拽组件 自由拖拽,垂直水平拖拽
import React, { useEffect, useState } from "react" import { Tree, message } from 'antd'; / ...
- draggable拖拽组件使用
项目开发中需要用到拖拽组件,因为前端技术框架是vue,这里就使用了vue的一款拖拽插件vue.draggable,一般基本的需求都能满足,这里使用了多个draggable嵌套,达到两级之前相互拖拽的功 ...
- Vue 实现拖拽模块(三)自定义拖拽组件的样式
上文介绍了 自定义拖拽组件位置 的简单实现,本文将继续给大家分享如何自定义拖拽组件位置的简单实现,文中通过示例代码介绍,感兴趣的小伙伴们可以了解一下 本文主要介绍了 Vue 自定义拖拽组件的样式,具体 ...
最新文章
- python类的成员函数_python特殊成员函数
- Open3d学习计划—高级篇 5(RGBD融合)
- 小程序开发需要注意什么
- Science:人类迎来目前最为全面的癌症染色质可及性图谱
- 【ZooKeeper Notes 30】ZooKeeper与Diamond有什么不一样
- 云生态战略首次曝光,牵手精诚中国和神州光大共建云生态
- java从键盘上录入学生人数和每个学生的姓名以及分数,按照分数降序输出,学生名次、学生姓名、学生分数
- 数据库笔记11:创建与管理存储过程
- Grand Central Dispatch(GCD)
- php金币格式转换,php 资金格式转换函数_PHP教程
- 基于JAVA+SpringBoot+Vue+Mybatis+MYSQL的宿舍管理系统
- Typora Mermaid 使用指南
- Win10 PC 能打电话了?腾讯追讨前员工 1940 万;淘宝进军 MR 购物 | 极客头条
- c语言正则表达式库,c语言正则表达式库--PCRE
- 分治法(divide conquer)与动态规划(dynamic programming)应用举例
- windows 编程 —— 子窗口 与 子窗口控件
- 用emoji表情提交代码指南
- 地面控制点的作用_地下室人防预留预埋施工要点及控制点
- Smartdrv程序有什么作用
- 51单片机流水灯实验