【问题标题】:Pinch-To-Zoom with Unity 5 UI使用 Unity 5 UI 进行捏合缩放
【发布时间】:2017-01-27 19:05:56
【问题描述】:

我正在尝试在基于 Unity UI 的应用中重新实现捏拉缩放系统。大约六个月前,我能够通过将 UI 画布作为常规 GameObject 的子对象并操纵该对象的变换来破解一个,但自从更新到 Unity 5.5+ 后,我发现这不起作用。我能得到的最接近的允许捏合手势更改画布的 scaleFactor,这 a) 可以使图像、面板等根据它们的对齐方式不正确地调整大小,并且 b) 缩放后将不允许我平移。

到目前为止,我所拥有的是:

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

正如我所说,这在一定程度上有效,但不能很好地统一缩放,也不能让我平移画布。提前感谢您的帮助。

【问题讨论】:

    标签: c# user-interface unity3d unity5 pinchzoom


    【解决方案1】:

    将此脚本附加到要放大和缩小的画布对象中

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

    提醒:此脚本仅适用于画布对象

    【讨论】:

      【解决方案2】:

      您可以使用此函数(只需将负 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 ();
      }
      

      对于平移, 你可以使用这样的东西:

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

      只需从事件触发器组件中调用函数 ( BeginDrag & Drag )。

      【讨论】:

        【解决方案3】:

        我使用捏合缩放对象是这样的,当对象位于屏幕中间时,它可以在任何触摸屏上工作:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-02-07
          • 2017-03-24
          • 1970-01-01
          • 1970-01-01
          • 2016-11-08
          • 2011-11-26
          • 2013-01-18
          • 2014-11-02
          相关资源
          最近更新 更多