适用于 Android/IOS 的 Canvas 上的 Unity 平滑移动和缩放 UI

Posted

技术标签:

【中文标题】适用于 Android/IOS 的 Canvas 上的 Unity 平滑移动和缩放 UI【英文标题】:Unity Smooth Move and Zoom UI on Canvas for Android/IOS 【发布时间】:2021-06-30 21:58:59 【问题描述】:

我为我的任务编写了这个脚本,在论坛上冲浪后我找不到好的决定,所以我为你们修改了代码并发布了这个。也许有人会有用。如果你有一些修改,我会很高兴听到?

【问题讨论】:

你应该在reddit或其他地方发布这个:) 【参考方案1】:
using UnityEngine;

public class MovableScrollRectFree : MonoBehaviour

    [Space(2)][Header("Settings")]
    // Content need set Anchor Presets [Middle & Center]
    [SerializeField] private GameObject Content;
    
    [Space(10)]
    [SerializeField] private float MinZoom = 0.5f;
    [SerializeField] private float MaxZoom = 3f;
    [SerializeField] private float ZoomSpeed = -0.002f;
    [SerializeField] private float MoveSpeed = 1f;

    [Space(10)] 
    [SerializeField] [Range(1, 10)] private int SmoothMove = 6;
    [SerializeField] [Range(1, 10)] private int SmoothScale = 6;
    
    [Space(10)] 
    // Can be zero values
    [SerializeField] private float MinPermissibleHeightOffset;
    [SerializeField] private float MaxPermissibleHeightOffset;
    [SerializeField] private float MinPermissibleWidthOffset;
    [SerializeField] private float MaxPermissibleWidthOffset;

    private RectTransform ContentRect;
    private Vector2 ContentSizeDelta;
    
    private Vector2 TargetScale;
    private Vector2 TargetPosition;

    private float moveMagnitude;
    private float scaleMagnitude;
    
    private float oldMoveMagnitude;
    private float oldScaleMagnitude;
    private float startScaleMagnitude;
    private float newScaleMagnitude;
    
    private Vector2 ContentScaleOnStart;
    private Vector2 ContentPositionOnStart;
    
    private Vector2 startPostiton;
    private Vector2 newPosition;

    private Vector2 stepMove;
    private Vector3 stepScale;
    
    private int avalibleMoveSteps;
    private int avalibleScaleSteps;
    
    Vector2 fingerPosition1;
    Vector2 fingerPosition2;
    
    private bool _isPinching;
    private bool active;

    private void Awake()
    
        Input.multiTouchEnabled = true;
    

    void Start()
    
        ContentRect = Content.GetComponent<RectTransform>();
        ContentSizeDelta = ContentRect.sizeDelta;
    

    private void Update()
    
        if (Input.touchCount == 2)
            active = true;
        else if (active)
        
            active = false;
            TryOutDangerZone();
            _isPinching = false;
        
    

    private void FixedUpdate()
    
        TransformContent();
        
        if (!active) return;
        if (Input.touchCount != 2) return;
        
        fingerPosition1 = Input.touches[0].position;
        fingerPosition2 = Input.touches[1].position;
        
        if (!_isPinching)
        
            _isPinching = true;
            OnPinchStart();
        
        OnPinch();
    
    
    private void OnPinchStart()
    
        startPostiton = GetMidlePosition(fingerPosition1, fingerPosition2);
        startScaleMagnitude = (fingerPosition1 - fingerPosition2).magnitude;
        ContentScaleOnStart = ContentRect.localScale;
        ContentPositionOnStart = ContentRect.anchoredPosition;
    
    
    private void OnPinch()
    
        newPosition = GetMidlePosition(fingerPosition1, fingerPosition2);

        oldMoveMagnitude = moveMagnitude;
        oldScaleMagnitude = scaleMagnitude;
        
        moveMagnitude = (newPosition - startPostiton).magnitude;
        
        newScaleMagnitude = (fingerPosition1 - fingerPosition2).magnitude;
        scaleMagnitude = startScaleMagnitude - newScaleMagnitude;


        if (Mathf.Abs(scaleMagnitude - oldScaleMagnitude) > 1 ||
            Mathf.Abs(moveMagnitude - oldMoveMagnitude) > 1)
        
            CalculateScaleContent();
            CalculateMoveContent();
        
    

    private void TransformContent()
    
        if (avalibleScaleSteps > 0)
        
            ContentRect.localScale += stepScale * (avalibleScaleSteps / 2f);
            avalibleScaleSteps--;
        
        
        if (avalibleMoveSteps > 0)
        
            ContentRect.anchoredPosition += stepMove * (avalibleMoveSteps / 2f);
            avalibleMoveSteps--;
        
    

    private void CalculateScaleContent()
    
        float tempScale = Mathf.Clamp(ContentScaleOnStart.x + (scaleMagnitude * ZoomSpeed), MinZoom, MaxZoom);
        
        TargetScale = new Vector2(tempScale, tempScale);
        
        stepScale = (TargetScale - (Vector2)ContentRect.localScale) / SmoothScale;
        avalibleScaleSteps = SmoothScale;
    

    private void CalculateMoveContent()
    
        Vector2 localScale = ContentRect.localScale;
        float maxMoveOffsetX = Mathf.Abs((ContentSizeDelta.x * localScale.x) - ContentSizeDelta.x) / 2 + MaxPermissibleWidthOffset;
        float maxMoveOffsetY = Mathf.Abs((ContentSizeDelta.y * localScale.y) - ContentSizeDelta.y) / 2 + MaxPermissibleHeightOffset;
        float offcetMoveX = newPosition.x - startPostiton.x;
        float offcetMoveY = newPosition.y - startPostiton.y;

        TargetPosition = new Vector2(
            Mathf.Clamp(ContentPositionOnStart.x + (offcetMoveX * MoveSpeed), -maxMoveOffsetX, maxMoveOffsetX),
            Mathf.Clamp(ContentPositionOnStart.y + (offcetMoveY * MoveSpeed), -maxMoveOffsetY, maxMoveOffsetY));
        
        stepMove = (TargetPosition - ContentRect.anchoredPosition) / SmoothMove;
        avalibleMoveSteps = SmoothMove;
    

    private void TryOutDangerZone()
    
        Vector2 localScale = ContentRect.localScale;
        float maxMoveOffsetX = Mathf.Abs((ContentSizeDelta.x * localScale.x) - ContentSizeDelta.x) / 2 + MinPermissibleWidthOffset;
        float maxMoveOffsetY = Mathf.Abs((ContentSizeDelta.y * localScale.y) - ContentSizeDelta.y) / 2 + MinPermissibleHeightOffset;

        TargetPosition = new Vector2(
            Mathf.Clamp(TargetPosition.x, -maxMoveOffsetX, maxMoveOffsetX),
            Mathf.Clamp(TargetPosition.y, -maxMoveOffsetY, maxMoveOffsetY));
        
        stepMove = (TargetPosition - ContentRect.anchoredPosition) / SmoothMove;
        avalibleMoveSteps = SmoothMove;
    
    
    private Vector2 GetMidlePosition(Vector2 pos1, Vector2 pos2)
    
        return Vector2.Lerp(pos1, pos2, 0.5f);
    

【讨论】:

以上是关于适用于 Android/IOS 的 Canvas 上的 Unity 平滑移动和缩放 UI的主要内容,如果未能解决你的问题,请参考以下文章

适用于 android、ios 和 blackberry 的 Codenameone 应用内计费

通过 PhoneGap 中的短信分享手机地理位置坐标(适用于 Android/IOS)

适用于 Android、iOS 和 PC 的通用跨平台应用程序 - 理论上 [关闭]

带有一个适用于android、ios、web的插件的flutter firebase(实时)数据库? [复制]

Canvas.toDataURL() 适用于除 IE10 以外的所有浏览器

适用于不同设备的响应式画布