在 Unity 中使用捏合手势缩放滚动视图内容的正确方法是什么?

2024-01-14

目标:制作一个通用组件,支持捏合缩放设备和滚动鼠标缩放编辑器。捏合时,将枢轴设置为两个手指的中点,这样它就会围绕您捏合的位置缩放。

我在下面提供了我的脚本。然而,当它“跳跃”或抖动很多时,它在两根手指捏合的设备上的滚动视图中效果不佳。不过,它可以在编辑器中使用鼠标滚动。我认为原因可能与滚动视图内部更新布局的方式有关。在单帧中,我的脚本更改了内容的轴心和位置,但是滚动视图无法正确处理这些更改。这就是为什么我还使用 1 LateUpdate、2ield WaitForEndOfFrame、3 在滚动视图的 OnValueChanged 事件中注册回调来测试我的脚本,但都失败了。

有谁知道如何解决我的脚本中的问题或任何其他新的解决方案如何制作滚动视图以支持捏合缩放?谢谢!

我的代码是这样的:

using System.Collections; 
using System.Collections.Generic; 
using UnityEngine; 
using UnityEngine.EventSystems;

public class PinchZoom : MonoBehaviour {
    public float zoomSpeedPinch = 0.001f;
    public float zoomSpeedMouseScrollWheel = 0.05f;
    public float zoomMin = 0.1f;
    public float zoomMax = 1f;
    RectTransform rectTransform;
    public int type = 1; // for device testing type 1 use LateUpdate; type 2 use Update

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

    //public void OnValueChanged(Vector2 v) // test failed: called by scroll view event
    //{
    //    //Zoom();
    //}

    void Update()
    {
        //Zoom();
        if (type == 2)
        {
            if (Input.touchCount == 2)
                StartCoroutine(ZoomInTheEndOfFrame(Input.mouseScrollDelta.y, Input.touchCount, Input.GetTouch(0), Input.GetTouch(1), Input.mousePosition));
            else
                StartCoroutine(ZoomInTheEndOfFrame(Input.mouseScrollDelta.y, Input.touchCount, default(Touch), default(Touch), Input.mousePosition));
        }
    }

    private void LateUpdate()
    {
        if (type == 1) Zoom();
    }

    void Zoom()
    {
        var mouseScrollWheel = Input.mouseScrollDelta.y;
        float scaleChange = 0f;
        Vector2 midPoint = Vector2.zero;
        if (Input.touchCount == 2)
        {
            Touch touchZero = Input.GetTouch(0);
            Touch touchOne = Input.GetTouch(1);

            Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
            Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;

            float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude;
            float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;

            float deltaMagnitudeDiff = touchDeltaMag - prevTouchDeltaMag;

            scaleChange = deltaMagnitudeDiff * zoomSpeedPinch;

            midPoint = (touchOne.position + touchZero.position) / 2;
        }

        if (mouseScrollWheel != 0)
        {
            scaleChange = mouseScrollWheel * zoomSpeedMouseScrollWheel;
            midPoint = Input.mousePosition;
        }

        if (scaleChange != 0)
        {
            var scaleX = transform.localScale.x;
            scaleX += scaleChange;
            scaleX = Mathf.Clamp(scaleX, zoomMin, zoomMax);
            var size = rectTransform.rect.size;
            size.Scale(rectTransform.localScale);
            var parentRect = ((RectTransform)rectTransform.parent);
            var parentSize = parentRect.rect.size;
            parentSize.Scale(parentRect.localScale);
            if (size.x > parentSize.x && size.y > parentSize.y)
            {
                var p1 = Camera.main.ScreenToWorldPoint(midPoint); 
                var p2 = transform.InverseTransformPoint(p1); 
                var pivotP = rectTransform.pivot * rectTransform.rect.size; 
                var p3 = (Vector2)p2 + pivotP; 
                var newPivot = p3 / rectTransform.rect.size;
                newPivot = new Vector2(Mathf.Clamp01(newPivot.x), Mathf.Clamp01(newPivot.y));
                rectTransform.SetPivot(newPivot);
            }
            else
            {
                rectTransform.SetPivot(new Vector2(0.5f, 0.5f));
            }

            transform.localScale = new Vector3(scaleX, scaleX, transform.localScale.z);
        }
    }

    //private IEnumerator ZoomInTheEndOfFrame(float mouseScrollWheel, int touchCount, Touch touchZero, Touch touchOne, Vector3 mousePosition) // testing failed
    //{
    //    yield return new WaitForEndOfFrame();
    //    ZoomWithData(mouseScrollWheel, touchCount, touchZero, touchOne, mousePosition);
    //}

}

为了在不让图像“跳跃”的情况下更改枢轴,我使用了扩展脚本:

using UnityEngine;

public static class RectTranformExtension
{
    /// <summary>
    /// Set pivot without changing the position of the element
    /// </summary>
    public static void SetPivot(this RectTransform rectTransform, Vector2 pivot)
    {
        Vector3 deltaPosition = rectTransform.pivot - pivot;    // get change in pivot
        deltaPosition.Scale(rectTransform.rect.size);           // apply sizing
        deltaPosition.Scale(rectTransform.localScale);          // apply scaling
        deltaPosition = rectTransform.rotation * deltaPosition; // apply rotation

        rectTransform.pivot = pivot;                            // change the pivot
        rectTransform.localPosition -= deltaPosition;           // reverse the position change
    }
}

经过几天的努力,我终于解决了这个问题。 解决方案是调用Zoom() in OnDrag(),并阻止 scollView 组件在缩放时接收拖动相关事件。 如果你想使用它,只需复制我下面的代码即可,不要做任何更改。这是我在设备上进行了大量测试后得到的结果。有一些潜在的小问题,细节太多,我不想解释,只是复制并使用它。我还建议使用当前 content.scale.x * 0.001 的速度

Codes:

// please note that scrollRect is the component on the scroll view game object, not where this script is

public void OnDrag(PointerEventData eventData)
{
    Zoom();
    if (Input.touchCount <= 1) scrollRect.OnDrag(eventData);
}

public void OnEndDrag(PointerEventData eventData)
{
    scrollRect.OnEndDrag(eventData);
}

public void OnBeginDrag(PointerEventData eventData)
{
    if (Input.touchCount <= 1) scrollRect.OnBeginDrag(eventData);
}

附:在原始脚本中,有一部分如果未通过边界检查,则将枢轴设置为 (0.5,0.5)。这部分需要注释掉(如果检查不通过则不需要更改pivot)。

另一件事是,您可以使用任何您想要的父子关系,但您必须确保接收 onDrag 事件的对象具有完整的图像来捕获事件。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Unity 中使用捏合手势缩放滚动视图内容的正确方法是什么? 的相关文章

随机推荐

  • 无法在 Web 配置中使用 applicationInitialization 预热页面

    我有一个简单的 Umbraco 7 7 2 应用程序 并将其托管在 Azure 应用程序服务 上 当我重新启动服务器时 第一次请求页面需要 20 40 秒 这真的很烦人 特别是当负载很高并且您处于横向扩展以减少响应时间 我已经在 webco
  • 检查输入的数字是否是 jquery 中的数字

    我有一个简单的textbox用户在其中输入号码 jQuery 有吗isDigit如果用户输入数字以外的内容 该功能将允许我显示警报框 该字段也可以有小数点 我建议使用正则表达式 var intRegex d var floatRegex d
  • Silverlight 的替代 IDE

    我想在不购买 Visual Studio 2008 许可证的情况下使用 silverlight 我已经使用了 Visual Studio 的试用时间 因此我正在尝试寻找另一个解决方案 外面有什么东西吗 Thanks RC0 及更高版本支持
  • Hadoop MapReduce 容器以非零退出代码 1 退出

    我正在尝试运行一些 hadoop 程序来提取 Ubuntu 中一些摘要的关键字 当我使用 Hadoop 运行程序时 出现以下错误 WARN util NativeCodeLoader Unable to load native hadoop
  • 从 javascript 将焦点设置到 Silverlight 控件

    我在使用 Silverlight 时遇到焦点问题 如何使用 JavaScript 将焦点设置到 Silverlight 控件 将以下内容添加到您的 Silverlight 托管页面 位于 onSilverlightError 函数上方 fu
  • 在 Java 中处理法语字符

    我有一个页面 我在其中搜索一个术语 并且它显示得很完美 无论它是什么字符类型 现在 当我在 JSP 中有几个复选框时 我会检查它并提交 在这些复选框中 我有一个框名称 例如ABC Farmac utica Corporation 当我单击提
  • 从字符串生成用于加密的整数,反之亦然

    我正在尝试用 python3 编写 RSA 代码 我需要将用户输入字符串 包含任何字符 而不仅仅是数字 转换为整数 然后对其进行加密 在 Python 3 6 中 在没有第 3 方模块的情况下将字符串转换为整数的最佳方法是什么 如何将字符串
  • jQuery 中同时具有 mousedown/mouseup 和 dblclick

    每当 mousedown 或 mouseup 处理程序附加到元素时 dblclick 就无法附加 如果附加则不起作用 尽管这看起来很公平 是否有任何方法可以恢复 dblclick 功能而不从头开始重写它 叹息 或者我错过了一些关于事件传播的
  • 异步操作完成,但结果未发送到浏览器

    我想实现一个网络聊天 后端是双 WCF 通道 双通道工作在控制台或winform中 它实际上可以在网络上运行 我至少可以发送和接收消息 作为我使用的基础这篇博文 http blogs claritycon com blog 2011 04
  • Chrome 标签页和进程

    我正在阅读关于 chrome 的谷歌书籍 其中他们谈到了为什么每次创建新选项卡时 他们决定启动一个进程来托管浏览器选项卡 所以 2 个标签 2 个镀铬工艺 3 个选项卡 3 个镀铬工艺等等 对吗 但我打开了大约 20 个左右的选项卡 但在任
  • Ruby Iconv 可与 irb 和 ruby​​ 调试器配合使用,但不能在单元测试中使用

    我在 Ubuntu 10 04 64 位上运行 Ruby 1 8 7 和 Rails 2 3 5 我写了一个方法 应该采用这样的字符串 cole la D couverte 并输出这样的文件系统名称 ecole a la decouvert
  • 作为就业申请的一部分,c# MVC3(非托管)申请中的书面签名

    我正在尝试寻找类似的解决方案http www tenstreet com http www tenstreet com 我尝试在互联网和 Sourceforge 上查找 但我发现的所有内容都是关于加密数字签名 我将使用它 但不是我所缺少的
  • 错误验证 W3C HTML5 img noscript facebook.com

    我正在尝试将我的页面验证为 HTML 5 W3c 我有以下错误 此处不允许使用 img 元素 作为 noscript 元素的子元素 noscript 元素作为 head 的子元素时 必须仅包含以下子元素 link style 和 meta
  • 在 Windows 上为 django 开发设置 virtualenv,

    当我尝试使用安装 MySQL python 时 第一次设置 virtualenv pip E lt
  • 为什么guard是基于Alternative的?

    Why is guard基于Alternative guard Alternative f gt Bool gt f guard b is pure if b is True and empty if b is False 我问是因为gua
  • 如何在matlab中制作三对角矩阵?

    如何从向量 1 2 3 4 5 创建下面的矩阵 1 0 0 0 0 2 1 0 0 0 3 2 1 0 0 4 3 2 1 0 5 4 3 2 1 0 5 4 3 2 0 0 5 4 3 0 0 0 5 4 0 0 0 0 5 这不是三对角
  • 是否可以使用 JQuery 或 JavaScript 更改窗口大小?

    我将创建 5 个按钮 例子 Button1 s value 640 480 Button2 s value 1024 600 Button3 s value 1600 900 Button4 s value 800 600 如果用户单击按钮
  • 通过 kinesis 触发跨账户 lambda

    我试图通过帐户 A 中的 Kinesis 流触发帐户 B 中的 lambda 这与描述的类似here https aws amazon com blogs compute easy authorization of aws lambda f
  • 连接属于表格行的 CSS 元素之间的垂直线

    我想用一条垂直线连接一些 CSS 圆圈 我尝试使用伪元素 after选择器如下 circle height 45px width 45px border radius 50 border 2px solid position relativ
  • 在 Unity 中使用捏合手势缩放滚动视图内容的正确方法是什么?

    目标 制作一个通用组件 支持捏合缩放设备和滚动鼠标缩放编辑器 捏合时 将枢轴设置为两个手指的中点 这样它就会围绕您捏合的位置缩放 我在下面提供了我的脚本 然而 当它 跳跃 或抖动很多时 它在两根手指捏合的设备上的滚动视图中效果不佳 不过 它