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