Unity 手指控制UGUI元素放大缩小 日期:2025-06-11 人气:1 - 新增一个脚本如下: ``` using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UIElements; public class MultiTouchZoom : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler { public bool isPrecision = true; //是否是精准拖拽 private RectTransform m_rect; private Vector3 m_offset; private Touch oldTouch1; //上次触摸点1(手指1) private Touch oldTouch2; //上次触摸点2(手指2) private float scaleRatio; // 缩放比例 // Start is called before the first frame update void Start() { m_rect = transform.GetComponent<RectTransform>(); scaleRatio = transform.localScale.x / transform.localScale.y; } // Update is called once per frame void Update() { //多点触摸, 放大缩小 if (2 == Input.touchCount) { Touch newTouch1 = Input.GetTouch(0); Touch newTouch2 = Input.GetTouch(1); // 只有手指在UGUI上才生效 if (!IsTouchOnImage(newTouch1.position) && !IsTouchOnImage(newTouch2.position)) { return; } // 刚开始接触屏幕, 只记录,不做处理 if (newTouch2.phase == TouchPhase.Began) { oldTouch2 = newTouch2; oldTouch1 = newTouch1; return; } /* 计算缩放倍数 */ float oldDistance = Vector2.Distance(oldTouch1.position, oldTouch2.position); float newDistance = Vector2.Distance(newTouch1.position, newTouch2.position); Vector3 scale = CalZoomScaleByRatio(newDistance, oldDistance); // 最小缩放到1倍,最大放大到5倍 if (scale.x >= scaleRatio * 1f && scale.y >= 1f && scale.x <= scaleRatio * 5 && scale.y <= 5 && transform.localScale != scale) { float old_Scare = transform.localScale.x; //原缩放比例 transform.localScale = scale; // 缩放 /* 缩放之后更改位置,防止图片移动到屏幕外 */ //缩放中心屏幕坐标转RectTransform下坐标 Vector2 center_Local; RectTransformUtility.ScreenPointToLocalPointInRectangle(m_rect, (newTouch2.position + newTouch1.position) / 2, Camera.main, out center_Local); //计算中心坐标的当前位置 float scaleFactor = CalZoomScaleFactorByRatio(newDistance, oldDistance); // 缩放因子和上面缩放比例要一致 float old_px = center_Local.x / old_Scare; float old_py = center_Local.y / old_Scare; float cur_pxPos = old_px * scaleFactor; float cur_pyPos = old_py * scaleFactor; //计算偏移量 float deltaX = center_Local.x - cur_pxPos; float deltaY = center_Local.y - cur_pyPos; m_rect.localPosition += new Vector3(deltaX, deltaY, 0); // 更改位置 } //记住最新的触摸点,下次使用 oldTouch1 = newTouch1; oldTouch2 = newTouch2; } } public void OnBeginDrag(PointerEventData eventData) { if (1 != Input.touchCount) { return; } Vector3 tWorldPos; if (isPrecision) { RectTransformUtility.ScreenPointToWorldPointInRectangle(m_rect, eventData.position, eventData.pressEventCamera, out tWorldPos); m_offset = transform.position - tWorldPos; } else { m_offset = Vector3.zero; } SetDraggedPosition(eventData); } public void OnDrag(PointerEventData eventData) { if (1 != Input.touchCount) { return; } SetDraggedPosition(eventData); } public void OnEndDrag(PointerEventData eventData) { if (1 != Input.touchCount) { return; } SetDraggedPosition(eventData); } /// <summary> /// 设置位置 /// </summary> /// <param name="eventData"></param> private void SetDraggedPosition(PointerEventData eventData) { //存储当前鼠标所在位置 Vector3 globalMousePos; //UI屏幕坐标转换为世界坐标 if (RectTransformUtility.ScreenPointToWorldPointInRectangle(m_rect, eventData.position, eventData.pressEventCamera, out globalMousePos)) { //设置位置及偏移量 m_rect.position = globalMousePos + m_offset; } } /// <summary> /// 根据距离计算缩放scale /// </summary> /// <param name="newDistance"></param> /// <param name="oldDistance"></param> /// <returns></returns> private Vector3 CalZoomScaleByDistance(float newDistance, float oldDistance) { float scaleFactor = CalZoomScaleFactorByDistance(newDistance, oldDistance); Vector3 localScale = transform.localScale; Vector3 scale = new Vector3(localScale.x + scaleFactor * scaleRatio, localScale.y + scaleFactor, localScale.z); return scale; } private float CalZoomScaleFactorByDistance(float newDistance, float oldDistance) { //两个距离之差,为正表示放大手势, 为负表示缩小手势 float offset = newDistance - oldDistance; //放大因子, 一个像素按 0.01倍来算(100可调整) float scaleFactor = offset / 100f; return scaleFactor; } /// <summary> /// 根据比例设置缩放 /// </summary> /// <param name="newDistance"></param> /// <param name="oldDistance"></param> /// <returns></returns> private Vector3 CalZoomScaleByRatio(float newDistance, float oldDistance) { // 算法2,计算比例 float scaleFactor = CalZoomScaleFactorByRatio(newDistance, oldDistance); Vector3 scale = transform.localScale * scaleFactor; return scale; } private float CalZoomScaleFactorByRatio(float newDistance, float oldDistance) { return newDistance / oldDistance; ; } /// <summary> /// 是否在图片上触摸 /// </summary> /// <param name="screenPosition"></param> /// <returns></returns> private bool IsTouchOnImage(Vector2 screenPosition) { Camera canvasCamera = GetComponentInParent<Canvas>().worldCamera; return RectTransformUtility.RectangleContainsScreenPoint(m_rect, screenPosition, canvasCamera); } } ``` - 为要拖动的UGUI元素添加上面新增的组件 - 勾选元素的属性`Raycast Target`,这一步切记,否则无法触发拖拽事件  ### 鸣谢 - [csdn**Keep-curiosity**](https://blog.csdn.net/Memoryuuu/article/details/106803596) - [博客园**草莓♭布丁**](https://www.cnblogs.com/strawberryPudding/p/15045307.html) 标签: 上一篇:vscode使用Community Server Connector运行JDK1.8项目报错 下一篇:Unity打包webgl之后中文字体不显示的问题 随便看看 2025-07-04 vscode使用Community Server Connector运行JDK1.8项目报错 2025-07-03 vscode中为maven项目指定java版本 2025-06-27 利用puppeteer将网页保存为pdf 2025-06-27 一天二十四时辰表 2025-06-27 家谱中儿子和父母的关系有哪些? 留言