unity 限制范围拖拽UI

/*************************************************************************
 *  Copyright © #COPYRIGHTYEAR# LiuKe. All rights reserved.
 *------------------------------------------------------------------------
 *  File         :  DragHandlerCopy.cs
 *  Description  :  Null.
 *------------------------------------------------------------------------
 *  Author       :  LiuKe
 *  Version      :  0.1.0
 *  Date         :  #CREATEDATE#
 *  Description  :  Initial development version.
 *************************************************************************/

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using DG.Tweening;
using System.Collections.Generic;
using UnityEngine.Events;

namespace LiuKe.Script
{
    //[AddComponentMenu("")]
    //[RequireComponent(typeof())]
    public class DragHandlerCopy : MonoBehaviour, IDragHandler, IBeginDragHandler,
    IEndDragHandler, IScrollHandler, IPointerDownHandler, IPointerUpHandler
    {
        public RectTransform RangePanel;
        public RectTransform MovePanel;
        public bool AllowOutOfPanel = false;
        public Vector2 rangeOffset = Vector2.zero;

        /// <summary>
        /// 强制将MovePanel坐标和鼠标一致
        /// </summary>
        public bool ForceSyncMouse = false;
        public bool LockX = false;
        public bool LockY = false;
        /// <summary>
        /// 启用惯性
        /// </summary>
        public bool EnableInertia = false;
        public float InertiaIntensity = 2f;

        public bool EnableScale = false;
        public float scaleSpeed = 12f;
        public float minScale = 1f;
        public float maxScale = 10f;

        Dictionary<int, Vector2> dic_Touch = new Dictionary<int, Vector2>(5);

        List<float> mDragTime = new List<float>();
        List<Vector3> mDragValue = new List<Vector3>();

        float MoveDuration = 0.5f;
        float MoveDeltaTime = 0.1f;
        public bool isMoving = false;

        public enum DragAction
        {
            Begin,
            Draging,
            End
        }

        public UnityAction<PointerEventData, DragAction> DragEvent;

        private void Start()
        {

        }

        private void OnDisable()
        {
            isMoving = false;
            DOTween.Kill(MovePanel);
        }

        public void OnDrag(PointerEventData eventData)
        {
            if (dic_Touch.Count < 1)
                return;
            isMoving = true;

            Bounds prevTouchBox = GetBounds();
            Vector2 oldPos;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(
                MovePanel.parent as RectTransform, prevTouchBox.center, eventData.pressEventCamera, out oldPos);

            dic_Touch[eventData.pointerId] = eventData.position;
            Bounds currBox = GetBounds();
            Vector2 mousePos;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(
                MovePanel.parent as RectTransform, currBox.center, eventData.pressEventCamera, out mousePos);
            //MovePanel.localPosition = mousePos;
            //
            if (Input.GetMouseButton(0))
                Move(oldPos, mousePos);
            //
            Scale(prevTouchBox, currBox, mousePos);

            if ((mousePos - oldPos).magnitude > 0f && DragEvent != null)
            {
                DragEvent(eventData, DragAction.Draging);
            }
        }

        public void Move(Vector2 oldPos, Vector2 curr)
        {
            RectTransform rectTrans = MovePanel;
            Vector2 nowLocal = rectTrans.localPosition;
            // 平移
            if (LockX)
                curr.x = nowLocal.x;
            if (LockY)
                curr.y = nowLocal.y;
            Vector2 offset = (curr - oldPos);
            Vector2 newPos;
            if (ForceSyncMouse)
            {
                newPos = curr;
            }
            else
            {
                newPos = nowLocal;
                newPos += offset;
            }

            newPos = GetFitPosition(newPos);
            rectTrans.localPosition = newPos;
            if (EnableInertia)
            {
                float curTime = Time.time;
                if (mDragTime.Count < 16)
                {
                    mDragTime.Add(curTime);
                    mDragValue.Add(offset);
                }
                else
                {
                    int index = 0;
                    float oldtime = mDragTime[index];
                    for (int i = 0; i < mDragTime.Count; i++)
                    {
                        if (mDragTime[i] < oldtime)
                        {
                            oldtime = mDragTime[i];
                            index = i;
                        }
                    }

                    mDragTime[index] = curTime;
                    mDragValue[index] = offset;
                }
            }
        }

        public void Scale(Bounds prevTouchBox, Bounds currBox, Vector2 mouseLocalPos)
        {
            if (!EnableScale)
                return;

            Vector2 oldScale = MovePanel.localScale;
            float offset = 0;
            float oldDiagonal = (prevTouchBox.max - prevTouchBox.min).magnitude;
            float diagonal = (currBox.max - currBox.min).magnitude;
            offset = diagonal - oldDiagonal;
            offset *= 0.15f * Time.deltaTime;

            Vector3 newScale = new Vector3(oldScale.x + offset, oldScale.y + offset);
            SetScale(ref newScale);
            //
            Vector2 localPos = MovePanel.anchoredPosition;
            Vector2 posOffset = mouseLocalPos - localPos;
            posOffset /= oldScale.x;
            posOffset *= (newScale.x - oldScale.x);
            Vector2 newPos = localPos - posOffset;

            newPos = GetFitPosition(newPos);
            MovePanel.localPosition = newPos;
        }

        void SetScale(ref Vector3 newScale)
        {
            //bool isInRange = true;
            if (newScale.x > maxScale)
            {
                newScale.x = maxScale;
                newScale.y = maxScale;
                //isInRange = false;
            }
            else if (newScale.x < minScale)
            {
                newScale.x = minScale;
                newScale.y = minScale;
                //isInRange = false;
            }
            newScale.z = newScale.x;
            MovePanel.localScale = newScale;
            //return isInRange;
        }

        private Bounds GetBounds()
        {
            Bounds rect = new Bounds();
            bool isInit = false;
            foreach (KeyValuePair<int, Vector2> touch in dic_Touch)
            {
                if (!isInit)
                {
                    rect = new Bounds(touch.Value, Vector2.zero);
                    isInit = true;
                }
                else
                {
                    rect.Encapsulate(touch.Value);
                }
            }
            return rect;
        }

        public void OnBeginDrag(PointerEventData eventData)
        {
            if (!dic_Touch.ContainsKey(eventData.pointerId))
            {
                dic_Touch.Add(eventData.pointerId, eventData.position);
            }
            if (DragEvent != null)
            {
                DragEvent(eventData, DragAction.Begin);
            }
        }

        public void OnPointerDown(PointerEventData eventData)
        {
            if (ForceSyncMouse)
            {
                OnBeginDrag(eventData);
                OnDrag(eventData);
            }
        }

        public void OnPointerUp(PointerEventData eventData)
        {
            if (ForceSyncMouse)
            {
                OnEndDrag(eventData);
            }
        }

        public void OnEndDrag(PointerEventData eventData)
        {
            isMoving = false;
            if (dic_Touch.ContainsKey(eventData.pointerId))
            {
                dic_Touch.Remove(eventData.pointerId);
            }
            if (EnableInertia)
            {
                float curTime = Time.time;
                Vector3 offset = Vector3.zero;
                for (int i = 0; i < mDragTime.Count; i++)
                {
                    if (curTime - mDragTime[i] < MoveDeltaTime)
                    {
                        offset += mDragValue[i];
                    }
                }

                Vector3 targetpos = MovePanel.localPosition + offset * InertiaIntensity;
                targetpos = GetFitPosition(targetpos);
                MovePanel.DOLocalMove(targetpos, MoveDuration);
            }
            if (DragEvent != null)
            {
                DragEvent(eventData, DragAction.End);
            }
        }

        Vector3 GetFitPosition(Vector2 newPos)
        {
            if (AllowOutOfPanel)
            {
                return newPos;
            }
            else
            {
                if (RangePanel == null)
                {
                    Canvas canvas = GetComponentInParent<Canvas>();
                    if (canvas != null)
                    {
                        RangePanel = canvas.transform as RectTransform;
                    }
                }

                Vector2 maxSize = RangePanel.rect.size;
                maxSize += rangeOffset * 2f;
                Vector2 moveSize = MovePanel.rect.size * MovePanel.localScale;


                // 将目标的坐标从pivot转换到center
                Vector2 cPivot = new Vector2(0.5f, 0.5f);
                Vector2 centerPos = newPos - (MovePanel.pivot - cPivot) * moveSize;
                // 范围检测
                float maxX = 0;
                float maxY = 0;
                if (moveSize.x > maxSize.x)
                    maxX = moveSize.x / 2f - maxSize.x / 2f;
                else
                    maxX = maxSize.x / 2f + moveSize.x / 2f - moveSize.x;

                if (moveSize.y > maxSize.y)
                    maxY = moveSize.y / 2f - maxSize.y / 2f;
                else
                    maxY = maxSize.y / 2f + moveSize.y / 2f - moveSize.y;

                if (centerPos.x > maxX)
                    centerPos.x = maxX;
                else if (centerPos.x < -maxX)
                    centerPos.x = -maxX;

                if (centerPos.y > maxY)
                    centerPos.y = maxY;
                else if (centerPos.y < -maxY)
                    centerPos.y = -maxY;

                newPos = centerPos + (MovePanel.pivot - cPivot) * moveSize;
                return newPos;
                // print(minY + "," + maxY + "," + newPos.y);
            }
        }

        public void OnScroll(PointerEventData eventData)
        {
            if (!EnableScale)
                return;
            Vector2 oldScale = MovePanel.localScale;
            float offset = scaleSpeed * Time.deltaTime * eventData.scrollDelta.y;
            Vector3 newScale = new Vector2(oldScale.x + offset, oldScale.y + offset);


            SetScale(ref newScale);

            //
            Vector2 mousePos;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(
                MovePanel.parent as RectTransform, eventData.position, eventData.pressEventCamera, out mousePos);

            Vector2 localPos = MovePanel.localPosition;
            Vector2 posOffset = mousePos - localPos;
            posOffset /= oldScale.x;
            posOffset *= (newScale.x - oldScale.x);
            Vector2 newPos = localPos - posOffset;
            //target.anchoredPosition = newPos;
            newPos = GetFitPosition(newPos);
            MovePanel.localPosition = newPos;
        }
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值