问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Unity动态锚点缩放UI实现方案

创作时间:
作者:
@小白创作中心

Unity动态锚点缩放UI实现方案

引用
CSDN
1.
https://blog.csdn.net/weixin_41741510/article/details/144563180

在Unity UGUI开发中,传统的UI元素缩放方式通常以中心点为基准,这在某些场景下可能不够直观。本文将介绍一种以鼠标位置为基准点的动态锚点缩放方案,让缩放效果更加自然和符合用户预期。

一、效果演示(结尾附工程下载地址)

二、制作过程

简言

该功能主要包含三个核心部分:

  1. 动态修改Pivot(锚点)位置
  2. 缩放功能实现
  3. 拖拽功能实现

一、创建一个Image作为背景,并添加Mask组件作为遮罩(防止缩放的图片不会超出此Image的可见范围)

二、创建需要进行缩放和平移的Image,作为背景的子物体并挂载下面完整代码的脚本。

三、完整代码

using UnityEngine;
using UnityEngine.EventSystems;

public class MapScrollerActivePivot : MonoBehaviour, IBeginDragHandler, IDragHandler, IPointerEnterHandler, IPointerExitHandler
{
    private Vector3 lastMousePosition;
    private RectTransform rectTransform;
    bool isHover;

    private void Start()
    {
        rectTransform = GetComponent<RectTransform>();
    }

    private void Update()
    {
        if (isHover)
        {
            SetPivotWithMousePos(rectTransform);
            Scale(Input.GetAxis("Mouse ScrollWheel") * 2f);
        }
    }

    public void Scale(float scaleMultiplier, float minScale = -1)
    {
        if (scaleMultiplier == 0)
        {
            return;
        }
        var scale = transform.localScale;
        scale *= 1 + scaleMultiplier;
        if (minScale != -1 && scale.x < minScale)
        {
            scale = Vector3.one * minScale;
        }
        transform.localScale = scale;
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        lastMousePosition = Input.mousePosition;
    }

    public void OnDrag(PointerEventData eventData)
    {
        Vector3 delta = Input.mousePosition - lastMousePosition;
        Vector3 newPosition = transform.position + delta;
        transform.position = newPosition;
        lastMousePosition = Input.mousePosition;
    }

    /// <summary>
    /// 设置UI元素的pivot,不改变位置
    /// </summary>
    /// <param name="rectTransform">需要设置pivot的RectTransform </param>
    public void SetPivotWithMousePos(RectTransform rectTransform)
    {
        Vector3 point = rectTransform.position;
        Vector3 sizeDelta = rectTransform.sizeDelta;
        Vector3 pivot = rectTransform.pivot;
        Vector3 mouseLocalPoint = rectTransform.InverseTransformPoint(Input.mousePosition);
        // 计算新的 pivot
        float x = (mouseLocalPoint.x + (pivot.x * sizeDelta.x)) / sizeDelta.x;
        float y = (mouseLocalPoint.y + (pivot.y * sizeDelta.y)) / sizeDelta.y;
        // 设置新的 pivot
        rectTransform.pivot = new Vector2(x, y);
        // 计算新的 position
        point.x += (x - pivot.x) * rectTransform.localScale.x * sizeDelta.x;
        point.y += (y - pivot.y) * rectTransform.localScale.y * sizeDelta.y;
        // 检查新位置是否有效
        if (!float.IsNaN(point.x) && !float.IsNaN(point.y) && !float.IsNaN(point.z))
        {
            rectTransform.position = point;
        }
        else
        {
            Debug.Log("计算的新位置无效: " + point);
        }
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        isHover = true;
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        isHover = false;
    }
}

四、总结

技术要点总结:

  1. 动态Pivot计算:通过InverseTransformPoint将鼠标世界坐标转换为UI元素本地坐标,实现精确的锚点计算。
  2. 位置补偿:修改Pivot会导致UI元素位置变化,需要通过计算偏移量来保持位置不变。
  3. 缩放控制:支持最小缩放限制,防止过度缩小导致的问题。
  4. 拖拽实现:使用EventSystem的拖拽接口,确保拖拽操作的准确性。

工程下载地址:

点击下载工程—蓝奏云
https://wwya.lanzoue.com/izPrL2j3jp7g

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号