【问题标题】:Fix for ScrollRect multi-touch in Unity?修复 Unity 中的 ScrollRect 多点触控?
【发布时间】:2019-05-20 12:32:31
【问题描述】:

目前,ScrollRect 在移动设备上的多点触控方面存在极大缺陷。

如果你自己尝试一下,你会发现每当你将两根手指放在屏幕上时,内容就会跳来跳去,并产生一些意想不到的行为。

有什么解决办法吗?目前,this 是我找到的唯一解决方案,但在某些情况下它仍然存在问题,最重要的是,它不能确定屏幕上所有手指的平均输入位置(或 MultiTouchPosition)。

这是我修改后的来自UnityUIExtensions bitbucket 的MultiTouchScrollRect.cs 脚本,但每次我将下一个手指放在屏幕上时它都会跳转:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class MultiTouchScrollRect : ScrollRect
{
    private int minimumTouchCount = 1, maximumTouchCount = 2, pointerId = -100;

    public Vector2 MultiTouchPosition
    {
        get
        {
            Vector2 position = Vector2.zero;
            for (int i = 0; i < Input.touchCount && i < maximumTouchCount; i++)
            {
                position += Input.touches[i].position;
            }
            position /= ((Input.touchCount <= maximumTouchCount) ? Input.touchCount : maximumTouchCount);
            return position;
        }
    }

    public override void OnBeginDrag(PointerEventData eventData)
    {
        if (Input.touchCount >= minimumTouchCount)
        {
            pointerId = eventData.pointerId;
            eventData.position = MultiTouchPosition;
            base.OnBeginDrag(eventData);
        }
    }
    public override void OnDrag(PointerEventData eventData)
    {
        if (Input.touchCount >= minimumTouchCount)
        {
            eventData.position = MultiTouchPosition;
            if (pointerId == eventData.pointerId)
            {
                base.OnDrag(eventData);
            }
        }
    }
    public override void OnEndDrag(PointerEventData eventData)
    {
        if (Input.touchCount >= minimumTouchCount)
        {
            pointerId = -100;
            eventData.position = MultiTouchPosition;
            base.OnEndDrag(eventData);
        }
    }
}

感谢您的宝贵时间!

【问题讨论】:

  • 好吧,如果你想要所有触摸之间的平均触摸位置......为什么当你添加触摸时它会跳转到另一个位置?例如之间的中心两点显然与第一点不一样……那么你期望会发生什么?
  • @derHugo 我正在尝试复制 iOS 照片查看器,因此您可以想象,当您将第二根手指向下放以进行缩放时,它不应该移动。
  • 那为什么不简单地坚持第一个而不是平均呢?
  • @derHugo 请亲自尝试一下。当您向下放置 2 个或更多手指时,Unity 的 ScrollRect 会出现问题。我正在寻找一种方法来解决这个问题。
  • 正如我所说,为什么不简单地只用第一根手指滚动而忽略其他手指,只使用其他手指进行缩放?

标签: c# android ios unity3d


【解决方案1】:

对于那些感兴趣的人,这是我编写的扩展 ScrollRect 类,它解决了这个问题:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace DanielLochner.Assets
{
    public class MultiTouchScrollRect : ScrollRect
    {
        #region Fields
        private int minimumTouchCount = 1, maximumTouchCount = 2, initialTouchCount = 0;
        #endregion

        #region Properties
        public Vector2 MultiTouchPosition
        {
            get
            {
                Vector2 position = Vector2.zero;
                for (int i = 0; i < Input.touchCount && i < maximumTouchCount; i++)
                {
                    position += Input.touches[i].position;
                }
                position /= ((Input.touchCount <= maximumTouchCount) ? Input.touchCount : maximumTouchCount);

                return position;
            }
        }
        #endregion

        #region Methods
        private void Update()
        {
            if (SystemInfo.deviceType == DeviceType.Handheld || UnityEditor.EditorApplication.isRemoteConnected)
            {
                if (Input.touchCount > 0)
                {
                    if (initialTouchCount == 0)
                    {
                        initialTouchCount = Input.touchCount;
                    }
                }
                else
                {
                    initialTouchCount = 0;
                }
            }
        }

        public override void OnBeginDrag(PointerEventData eventData)
        {
            if (SystemInfo.deviceType == DeviceType.Handheld || UnityEditor.EditorApplication.isRemoteConnected)
            {
                if (Input.touchCount >= minimumTouchCount && Input.touchCount == initialTouchCount)
                {
                    eventData.position = MultiTouchPosition;
                    base.OnBeginDrag(eventData);
                }
            }
            else if (SystemInfo.deviceType == DeviceType.Desktop)
            {
                base.OnBeginDrag(eventData);
            }
        }
        public override void OnDrag(PointerEventData eventData)
        {
            if (SystemInfo.deviceType == DeviceType.Handheld || UnityEditor.EditorApplication.isRemoteConnected)
            {
                if (Input.touchCount >= minimumTouchCount && Input.touchCount == initialTouchCount)
                {
                    eventData.position = MultiTouchPosition;
                    base.OnDrag(eventData);
                }
            }
            else if (SystemInfo.deviceType == DeviceType.Desktop)
            {
                base.OnDrag(eventData);
            }          
        }
        public override void OnEndDrag(PointerEventData eventData)
        {
            if (SystemInfo.deviceType == DeviceType.Handheld || UnityEditor.EditorApplication.isRemoteConnected)
            {
                if (Input.touchCount >= minimumTouchCount)
                {
                    eventData.position = MultiTouchPosition;
                    base.OnEndDrag(eventData);
                }
            }
            else if (SystemInfo.deviceType == DeviceType.Desktop)
            {
                base.OnEndDrag(eventData);
            }       
        }
        #endregion
    }
}

【讨论】:

  • 感谢丹尼尔的努力。但是代码: UnityEditor.EditorApplication.isRemoteConnected 在人们构建时会出错。所以我建议这样写:#if UNITY_EDITOR isRemoteConnected = UnityEditor.EditorApplication.isRemoteConnected; #endif if (SystemInfo.deviceType == DeviceType.Handheld || isRemoteConnected)
【解决方案2】:

试试这个(尚未测试):

public Vector2 MultiTouchPosition
{
    get
    {
        int nTouches = ((Input.touchCount <= maximumTouchCount) ? Input.touchCount : maximumTouchCount);
        if(nTouches == 1)
        {
             return Input.touches[0].position;
        } 
        else 
        {
             return Vector2.Lerp(Input.touches[0].position, Input.touches[1].position, 0.5f); //middle point between them
        }
    }
 }

由于您要处理的触摸量只能是一个或两个,因此最好以不同方式处理每个案例。

不知道你为什么要分位置,position是一个Vector2,你需要计算它们之间的中间点,可以用Vector2.Lerp来完成(0.5f决定你要中间点)

【讨论】:

  • 您好,感谢您的回答,但并不能解决问题。请回家后自己尝试一下!我除以触摸次数,因为这样可以确保我得到所有触摸之间的平均值(在 $min 和 $max 之间的触摸次数),而不仅仅是第一次和第二次触摸(就像你的答案一样)。
  • 分割Vector2绝对没问题。它只是将所有 3 个分量除以给定值 => 实际上,Daniel 在这里使用了正确的方法来获取两个以上向量的平均值。但是,Daniel,您的示例强烈建议最多接触 2,因此您应该明确说明它可能会更改甚至公开,以便您可以通过 Inspector 或从外部更改它,而不是硬编码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多