Unity UI:移动端UI Image捏合缩放功能实现求助
我之前也碰到过类似的需求——Sprite Render的缩放方案确实顺手,但UI Image因为属于UGUI体系,坐标和交互逻辑都不一样,用ScrollRect+Mask来实现缩放是个靠谱的思路,我来给你拆解下具体怎么做:
实现UI Image的移动端双指缩放(基于ScrollRect+Mask)
1. 搭建基础UI结构
首先在Canvas下创建如下层级:
- ScrollRect(添加Mask组件,勾选"Show Mask Graphic"可选)
- Viewport(ScrollRect默认自带,确保它的RectTransform和你想要显示的区域一致)
- Content(ScrollRect默认自带,把你的UI Image作为它的子物体)
- TargetImage(你要缩放的UI Image)
- Content(ScrollRect默认自带,把你的UI Image作为它的子物体)
- Viewport(ScrollRect默认自带,确保它的RectTransform和你想要显示的区域一致)
注意点:
- 把ScrollRect的
Horizontal和Vertical滚动都勾选上,后续可保留滚动+缩放的组合交互 - TargetImage的锚点设为
(0.5, 0.5),让它中心点对齐Content,方便后续缩放定位 - Content的RectTransform大小要设为TargetImage的原始尺寸(或更大),确保缩放时不会出现空白区域
2. 编写缩放交互脚本
给ScrollRect挂载一个C#脚本,处理移动端双指触摸的缩放逻辑,核心是计算缩放比例、调整Content的localScale,同时保证缩放中心是双指中点,避免画面偏移:
using UnityEngine; using UnityEngine.UI; public class UIImageZoom : MonoBehaviour { private ScrollRect _scrollRect; private RectTransform _contentRect; private Vector2 _lastTouchPos1; private Vector2 _lastTouchPos2; private float _lastDistance; public float minScale = 1f; public float maxScale = 3f; void Awake() { _scrollRect = GetComponent<ScrollRect>(); _contentRect = _scrollRect.content; // 初始化缩放为原始大小 _contentRect.localScale = Vector3.one; } void Update() { if (Input.touchCount == 2) { Touch touch1 = Input.GetTouch(0); Touch touch2 = Input.GetTouch(1); // 计算当前双指距离 Vector2 currentPos1 = touch1.position; Vector2 currentPos2 = touch2.position; float currentDistance = Vector2.Distance(currentPos1, currentPos2); if (touch1.phase == TouchPhase.Began || touch2.phase == TouchPhase.Began) { // 记录初始距离和触摸位置 _lastDistance = currentDistance; _lastTouchPos1 = currentPos1; _lastTouchPos2 = currentPos2; } else if (touch1.phase == TouchPhase.Moved && touch2.phase == TouchPhase.Moved) { // 计算缩放因子 float scaleFactor = currentDistance / _lastDistance; Vector3 newScale = _contentRect.localScale * scaleFactor; // 限制缩放范围,避免过度缩放 newScale = Vector3.ClampMagnitude(newScale, maxScale); newScale = Vector3.Max(newScale, Vector3.one * minScale); // 计算双指中点在Canvas上的位置 Vector2 midPoint = (currentPos1 + currentPos2) / 2; // 转换为Content的本地坐标 RectTransformUtility.ScreenPointToLocalPointInRectangle( _contentRect, midPoint, _scrollRect.GetComponentInParent<Canvas>().worldCamera, out Vector2 localMidPoint); // 计算缩放前后中点的偏移,调整Content位置保证缩放中心不变 Vector3 offset = _contentRect.TransformPoint(localMidPoint) - _contentRect.position; _contentRect.position += offset - (_contentRect.localScale / scaleFactor).Multiply(offset); // 应用最终缩放比例 _contentRect.localScale = newScale; // 更新上一帧数据,用于下一帧计算 _lastDistance = currentDistance; _lastTouchPos1 = currentPos1; _lastTouchPos2 = currentPos2; } } } }
3. 细节优化
- 如果你不需要滚动功能,可以把ScrollRect的
Horizontal和Vertical取消勾选,只保留缩放交互 - 调整
minScale和maxScale参数,适配你的业务需求,比如最小1倍(原始大小)、最大3倍放大 - 给TargetImage开启"Preserve Aspect"选项,避免缩放时出现拉伸变形
- 若需要单指拖动查看缩放后的大图,ScrollRect默认已经支持,只要Content大小超过Viewport即可
这个方案的好处是利用了UGUI原生组件,不需要额外的裁剪逻辑,移动端触摸交互也符合用户习惯,比直接修改Image的scale要更稳定,尤其适合需要配合滚动查看大图的场景。
内容的提问来源于stack exchange,提问作者Nanopl
相关产品推荐
相关产品推荐

