ios Unity?中ScrollRect多点触控的修复

ej83mcc0  于 2022-11-19  发布在  iOS
关注(0)|答案(3)|浏览(225)

目前,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);
        }
    }
}

感谢您抽出宝贵时间!

jfewjypa

jfewjypa1#

对于那些感兴趣的人,这是我编写的扩展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
    }
}
cygmwpex

cygmwpex2#

试试 这个 ( 尚未 测试 ) :

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
        }
    }
 }

中 的 每 一 个
由于 您 要 处理 的 接触 量 只能 是 一 个 或 两 个 , 因此 最 好 以 不同 的 方式 处理 每个 案例 。
我 不 知道 你 为什么 要 划分 位置 , 位置 是 一 个 Vector2 , 你 需要 计算 它们 之间 的 中点 , 这 可以 用 Vector2.Lerp 来 完成 ( 0.5f 决定 你 想要 的 中点 )

t2a7ltrp

t2a7ltrp3#

我有一个替代的实现,使用第一次触摸作为起点,并根据每次触摸的偏移进行更新。

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

namespace ScrollRect.Extensions
{
    public class MultiTouchScrollRect : ScrollRect
    {
        #region Fields
        private bool _draging = false;
        private Vector2 _dragOffset = Vector2.zero;
        private Dictionary<int, Vector2> _activePointers = new Dictionary<int, Vector2>();
        #endregion

        #region Properties
        public bool IsHandheld
        {
            get
            {
#if UNITY_EDITOR
                return UnityEditor.EditorApplication.isRemoteConnected;
#else
                return SystemInfo.deviceType == DeviceType.Handheld;
#endif
            }
        }

        #endregion

        #region Methods

        public override void OnBeginDrag(PointerEventData eventData)
        {
            if (eventData.button != PointerEventData.InputButton.Left)
                return;
            
            if (IsHandheld)
            {
                _activePointers[eventData.pointerId] = eventData.position;
                
                if (Input.touchCount >= 1 && !_draging)
                {
                    base.OnBeginDrag(eventData);
                    _draging = true;
                    _dragOffset = eventData.position;
                }
            }
            else if (SystemInfo.deviceType == DeviceType.Desktop)
            {
                base.OnBeginDrag(eventData);
            }
        }
        public override void OnDrag(PointerEventData eventData)
        {
            if (eventData.button != PointerEventData.InputButton.Left)
                return;
            
            if (IsHandheld)
            {
                if (Input.touchCount >= 1 && _activePointers.ContainsKey(eventData.pointerId))
                {
                    _dragOffset += eventData.position - _activePointers[eventData.pointerId];
                    _activePointers[eventData.pointerId] = eventData.position;
                    eventData.position = _dragOffset;
                    base.OnDrag(eventData);
                }
            }
            else if (SystemInfo.deviceType == DeviceType.Desktop)
            {
                base.OnDrag(eventData);
            }          
        }
        public override void OnEndDrag(PointerEventData eventData)
        {
            if (eventData.button != PointerEventData.InputButton.Left)
                return;
            
            if (IsHandheld)
            {
                if (_activePointers.ContainsKey(eventData.pointerId))
                {
                    _activePointers.Remove(eventData.pointerId);
                }
                
                if (Input.touchCount == 1)
                {
                    base.OnEndDrag(eventData);
                    _draging = false;
                    _dragOffset = Vector2.zero;
                }

            }
            else if (SystemInfo.deviceType == DeviceType.Desktop)
            {
                base.OnEndDrag(eventData);
            }       
        }
        #endregion
    }
}

相关问题