简体   繁体   English

使用 Unity 5 UI 进行双指缩放

[英]Pinch-To-Zoom with Unity 5 UI

I'm trying to re-implement a pinch-to-zoom system in a Unity UI-based app.我正在尝试在基于 Unity UI 的应用程序中重新实现双指缩放系统。 About six months ago I was able to hack one together by making the UI canvas a child of a regular GameObject, and manipulating that object's transform, but since updating to Unity 5.5+ I find this doesn't work.大约六个月前,我能够通过使 UI 画布成为常规 GameObject 的子项并操纵该对象的变换来一起破解一个,但自从更新到 Unity 5.5+ 后,我发现这不起作用。 The closest I can get allows the pinch gesture to change the canvas' scaleFactor, which a) can make images, panels, etc resize improperly depending on their alignments, and b) won't allow me to pan once zoomed.我能得到的最接近的允许捏手势改变画布的比例因子,这 a) 可以根据它们的对齐方式使图像、面板等不正确地调整大小,b) 一旦缩放就不允许我平移。

What I have so far is this:到目前为止,我所拥有的是:

public class PinchToZoomScaler : MonoBehaviour {

    public Canvas canvas; // The canvas
    public float zoomSpeed = 0.5f;        // The rate of change of the canvas scale factor

    public float _resetDuration = 3.0f;
    float _durationTimer = 0.0f;

    float _startScale = 0.0f;

    void Start() {
        _startScale = canvas.scaleFactor;
    }

    void Update()
    {
            // If there are two touches on the device...
            if (Input.touchCount == 2) {
                // Store both touches.
                Touch touchZero = Input.GetTouch (0);
                Touch touchOne = Input.GetTouch (1);

                // Find the position in the previous frame of each touch.
                Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
                Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;

                // Find the magnitude of the vector (the distance) between the touches in each frame.
                float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude;
                float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;

                // Find the difference in the distances between each frame.
                float deltaMagnitudeDiff = prevTouchDeltaMag - touchDeltaMag;

                // ... change the canvas size based on the change in distance between the touches.
                canvas.scaleFactor -= deltaMagnitudeDiff * zoomSpeed;

                // Make sure the canvas size never drops below 0.1
                canvas.scaleFactor = Mathf.Max (canvas.scaleFactor, _startScale);
                canvas.scaleFactor = Mathf.Min (canvas.scaleFactor, _startScale * 3.0f);

                _durationTimer = 0.0f;
            } else {
                _durationTimer += Time.deltaTime;

                if (_durationTimer >= _resetDuration) {
                    canvas.scaleFactor = _startScale;
                }
            }
    }
}

As I said, this works to a degree, but doesn't give me a nice uniform zooming, not does it allow me to pan the canvas.正如我所说,这在一定程度上有效,但不能给我一个很好的统一缩放,也不能让我平移画布。 Thanks in advance for any help.在此先感谢您的帮助。

Attach this script in canvas object which you want to zoom in and zoom out by pinch将此脚本附加到要放大和缩小的画布对象中

using UnityEngine;
using UnityEngine.EventSystems;

public class ObjectScalling : MonoBehaviour, IPointerDownHandler, IPointerUpHandler 
{
    private bool _isDragging;
    private float _currentScale;
    public float minScale, maxScale;
    private float _temp = 0;
    private float _scalingRate = 2;

    private void Start() 
    {
        _currentScale = transform.localScale.x;
    }

    public void OnPointerDown(PointerEventData eventData) 
    {
        if (Input.touchCount == 1) 
        {
            _isDragging = true;
        }
    }


    public void OnPointerUp(PointerEventData eventData) 
    {
        _isDragging = false;
    }


    private void Update() 
    {
        if (_isDragging)
            if (Input.touchCount == 2) 
            {
                transform.localScale = new Vector2(_currentScale, _currentScale);
                float distance = Vector3.Distance(Input.GetTouch(0).position, Input.GetTouch(1).position);
                if (_temp > distance) 
                {
                    if (_currentScale < minScale)
                        return;
                    _currentScale -= (Time.deltaTime) * _scalingRate;
                }

                else if (_temp < distance) 
                {
                    if (_currentScale > maxScale)
                        return;
                    _currentScale += (Time.deltaTime) * _scalingRate;
                }

                _temp = distance;
            }
    }
}

Reminder: This script only works in canvas objects提醒:此脚本仅适用于画布对象

You can use this function ( just pass to it negative deltaMagnitudeDiff ) Also it is good to multiplay deltaMagnitudeDiff with a ratio like ( 0.05 )您可以使用此函数(只需将负 deltaMagnitudeDiff 传递给它)此外,最好以 ( 0.05 ) 之类的比率多重播放 deltaMagnitudeDiff

float currentScale = 1f;
void Zoom (float increment)
{
    currentScale += increment;
    if (currentScale >= maxScale)
    {
        currentScale = maxScale;
    }
    else if (currentScale <= minScale)
    {
        currentScale = minScale;
    }
    rectTransform.localScale = new Vector3 (currentScale, currentScale, 1);

    pan.ValidatePosition ();
}

For Panning, you can use something like this :对于平移,您可以使用以下内容:

public class Pan : MonoBehaviour
{
    public float Speed;

    Vector3 startDragPosition;

    public void BeginDrag ()
    {
        startDragPosition = Input.mousePosition;
    }

    public void Drag ()
    {
        transform.localPosition += (Input.mousePosition - startDragPosition) * Speed;
        startDragPosition = Input.mousePosition;

        ValidatePosition ();
    }

    public void ValidatePosition ()
    {
        var temp = transform.localPosition;

        var width = ((RectTransform)transform).sizeDelta.x;
        var height = ((RectTransform)transform).sizeDelta.y;

        var MaxX = 0.5f * width * Mathf.Max (0, transform.localScale.x - 1);
        var MaxY = 0.5f * height * Mathf.Max (0, transform.localScale.y - 1);

        var offsetX = transform.localScale.x * width * (((RectTransform)transform).pivot.x - 0.5f);
        var offsetY = transform.localScale.y * width * (((RectTransform)transform).pivot.y - 0.5f);

        if (temp.x < -MaxX + offsetX)
            temp.x = -MaxX + offsetX;
        else if (temp.x > MaxX + offsetX)
            temp.x = MaxX + offsetX;

        if (temp.y < -MaxY + offsetY)
            temp.y = -MaxY + offsetY;
        else if (temp.y > MaxY + offsetY)
            temp.y = MaxY + offsetY;

        transform.localPosition = temp;
}

Just call the functions ( BeginDrag & Drag ) from the Events Trigger component.只需从事件触发器组件调用函数 ( BeginDrag & Drag )。

what i did to scale an object using pinch was this, it works on any touch screen when the object is in the middle of the screen:我使用捏缩放对象的操作是这样的,当对象位于屏幕中间时,它可以在任何触摸屏上工作:

if (Input.touchCount == 2)
        {
            //The distance between the 2 touches is checked and subsequently used to scale the
            //object by moving the 2 fingers further, or closer form eachother.
            Touch touch0 = Input.GetTouch(0);
            Touch touch1 = Input.GetTouch(1);
            if (isScaling)//this will only be done if scaling is true
            {
                float currentTouchDistance = getTouchDistance();
                float deltaTouchDistance = currentTouchDistance - touchDistanceOrigin;
                float scalePercentage = (deltaTouchDistance / 1200f) + 1f;

                Vector3 scaleTemp = transform.localScale;
                scaleTemp.x = scalePercentage * originalScale.x;
                scaleTemp.y = scalePercentage * originalScale.y;
                scaleTemp.z = scalePercentage * originalScale.z;

                //to make the object snap to 100% a check is being done to see if the object scale is close to 100%,
                //if it is the scale will be put back to 100% so it snaps to the normal scale.
                //this is a quality of life feature, so its easy to get the original size of the object.
                if (scaleTemp.x * 100 < 102 && scaleTemp.x * 100 > 98)
                {
                    scaleTemp.x = 1;
                    scaleTemp.y = 1;
                    scaleTemp.z = 1;
                }
                //here we apply the calculation done above to actually make the object bigger/smaller.
                transform.localScale = scaleTemp;


            }
            else
            {
                //if 2 fingers are touching the screen but isScaling is not true we are going to see if
                //the middle of the screen is looking at the object and if it is set isScalinf to true;
                Ray ray;
                RaycastHit hitTouch;
                ray = cam.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0));
                if (Physics.Raycast(ray, out hitTouch, 100f))
                {
                    if (hitTouch.transform == transform)
                    {
                        isScaling = true;
                        //make sure that the distance between the fingers on initial contact is used as the original distance
                        touchDistanceOrigin = getTouchDistance();
                        originalScale = transform.localScale;
                    }
                }
            }
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM