370 lines
9.4 KiB
C#
370 lines
9.4 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.UI;
|
|
|
|
namespace UIWidgets
|
|
{
|
|
public class SlideBlock : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler, IEventSystemHandler
|
|
{
|
|
[SerializeField]
|
|
[Tooltip("Requirements: start value should be less than end value; Recommended start value = 0; end value = 1;")]
|
|
public AnimationCurve Curve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
|
|
|
|
public SlideBlockAxis Direction;
|
|
|
|
[SerializeField]
|
|
private bool isOpen;
|
|
|
|
[SerializeField]
|
|
private bool scrollRectSupport;
|
|
|
|
[SerializeField]
|
|
private GameObject optionalHandle;
|
|
|
|
public UnityEvent OnOpen = new UnityEvent();
|
|
|
|
public UnityEvent OnClose = new UnityEvent();
|
|
|
|
private RectTransform rectTransform;
|
|
|
|
private Vector2 closePosition;
|
|
|
|
private IEnumerator currentAnimation;
|
|
|
|
private float size;
|
|
|
|
public bool IsOpen
|
|
{
|
|
get
|
|
{
|
|
return isOpen;
|
|
}
|
|
set
|
|
{
|
|
isOpen = value;
|
|
ResetPosition();
|
|
}
|
|
}
|
|
|
|
public bool ScrollRectSupport
|
|
{
|
|
get
|
|
{
|
|
return scrollRectSupport;
|
|
}
|
|
set
|
|
{
|
|
if (scrollRectSupport)
|
|
{
|
|
GetComponentsInChildren<ScrollRect>().ForEach(RemoveHandleEvents);
|
|
}
|
|
scrollRectSupport = value;
|
|
if (scrollRectSupport)
|
|
{
|
|
GetComponentsInChildren<ScrollRect>().ForEach(AddHandleEvents);
|
|
}
|
|
}
|
|
}
|
|
|
|
public GameObject OptionalHandle
|
|
{
|
|
get
|
|
{
|
|
return optionalHandle;
|
|
}
|
|
set
|
|
{
|
|
if (optionalHandle != null)
|
|
{
|
|
RemoveHandleEvents(optionalHandle);
|
|
}
|
|
optionalHandle = value;
|
|
if (optionalHandle != null)
|
|
{
|
|
AddHandleEvents(optionalHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected RectTransform RectTransform
|
|
{
|
|
get
|
|
{
|
|
if (rectTransform == null)
|
|
{
|
|
rectTransform = base.transform as RectTransform;
|
|
}
|
|
return rectTransform;
|
|
}
|
|
}
|
|
|
|
private string GetWarning()
|
|
{
|
|
Keyframe[] keys = Curve.keys;
|
|
if (keys[0].value >= keys[keys.Length - 1].value)
|
|
{
|
|
return string.Format("Curve requirements: start value (current: {0}) should be less than end value (current: {1}).", keys[0].value, keys[keys.Length - 1].value);
|
|
}
|
|
return string.Empty;
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
string warning = GetWarning();
|
|
if (warning != string.Empty)
|
|
{
|
|
Debug.LogWarning(warning, this);
|
|
}
|
|
closePosition = RectTransform.anchoredPosition;
|
|
size = ((!IsHorizontal()) ? RectTransform.rect.height : RectTransform.rect.width);
|
|
if (IsOpen)
|
|
{
|
|
if (Direction == SlideBlockAxis.LeftToRight)
|
|
{
|
|
closePosition = new Vector2(closePosition.x - size, closePosition.y);
|
|
}
|
|
if (Direction == SlideBlockAxis.RightToLeft)
|
|
{
|
|
closePosition = new Vector2(closePosition.x + size, closePosition.y);
|
|
}
|
|
else if (Direction == SlideBlockAxis.TopToBottom)
|
|
{
|
|
closePosition = new Vector2(closePosition.x, closePosition.y - size);
|
|
}
|
|
else if (Direction == SlideBlockAxis.BottomToTop)
|
|
{
|
|
closePosition = new Vector2(closePosition.x, closePosition.y + size);
|
|
}
|
|
}
|
|
OptionalHandle = optionalHandle;
|
|
ScrollRectSupport = scrollRectSupport;
|
|
}
|
|
|
|
private void AddScrollRectHandle()
|
|
{
|
|
GetComponentsInChildren<ScrollRect>().ForEach(AddHandleEvents);
|
|
}
|
|
|
|
private void RemoveScrollRectHandle()
|
|
{
|
|
GetComponentsInChildren<ScrollRect>().ForEach(RemoveHandleEvents);
|
|
}
|
|
|
|
private void AddHandleEvents(Component handleComponent)
|
|
{
|
|
AddHandleEvents(handleComponent.gameObject);
|
|
}
|
|
|
|
private void AddHandleEvents(GameObject handleObject)
|
|
{
|
|
SlideBlockHandle slideBlockHandle = handleObject.GetComponent<SlideBlockHandle>() ?? handleObject.AddComponent<SlideBlockHandle>();
|
|
slideBlockHandle.BeginDragEvent.AddListener(OnBeginDrag);
|
|
slideBlockHandle.DragEvent.AddListener(OnDrag);
|
|
slideBlockHandle.EndDragEvent.AddListener(OnEndDrag);
|
|
}
|
|
|
|
private void RemoveHandleEvents(Component handleComponent)
|
|
{
|
|
RemoveHandleEvents(handleComponent.gameObject);
|
|
}
|
|
|
|
private void RemoveHandleEvents(GameObject handleObject)
|
|
{
|
|
SlideBlockHandle component = handleObject.GetComponent<SlideBlockHandle>();
|
|
if (component != null)
|
|
{
|
|
component.BeginDragEvent.RemoveListener(OnBeginDrag);
|
|
component.DragEvent.RemoveListener(OnDrag);
|
|
component.EndDragEvent.RemoveListener(OnEndDrag);
|
|
}
|
|
}
|
|
|
|
private void ResetPosition()
|
|
{
|
|
if (isOpen)
|
|
{
|
|
size = ((!IsHorizontal()) ? RectTransform.rect.height : RectTransform.rect.width);
|
|
if (Direction == SlideBlockAxis.LeftToRight)
|
|
{
|
|
RectTransform.anchoredPosition = new Vector2(closePosition.x + size, RectTransform.anchoredPosition.y);
|
|
}
|
|
else if (Direction == SlideBlockAxis.RightToLeft)
|
|
{
|
|
RectTransform.anchoredPosition = new Vector2(closePosition.x - size, RectTransform.anchoredPosition.y);
|
|
}
|
|
else if (Direction == SlideBlockAxis.TopToBottom)
|
|
{
|
|
RectTransform.anchoredPosition = new Vector2(RectTransform.anchoredPosition.x, closePosition.y - size);
|
|
}
|
|
else if (Direction == SlideBlockAxis.BottomToTop)
|
|
{
|
|
RectTransform.anchoredPosition = new Vector2(RectTransform.anchoredPosition.x, closePosition.y + size);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RectTransform.anchoredPosition = closePosition;
|
|
}
|
|
}
|
|
|
|
public void Toggle()
|
|
{
|
|
if (IsOpen)
|
|
{
|
|
Close();
|
|
}
|
|
else
|
|
{
|
|
Open();
|
|
}
|
|
}
|
|
|
|
public void OnBeginDrag(PointerEventData eventData)
|
|
{
|
|
size = ((!IsHorizontal()) ? RectTransform.rect.height : RectTransform.rect.width);
|
|
}
|
|
|
|
public void OnEndDrag(PointerEventData eventData)
|
|
{
|
|
float num = ((!IsHorizontal()) ? (RectTransform.anchoredPosition.y - closePosition.y) : (RectTransform.anchoredPosition.x - closePosition.x));
|
|
if (num == 0f)
|
|
{
|
|
isOpen = false;
|
|
OnClose.Invoke();
|
|
return;
|
|
}
|
|
int num2 = ((!IsReverse()) ? 1 : (-1));
|
|
if (num == size * (float)num2)
|
|
{
|
|
isOpen = true;
|
|
OnOpen.Invoke();
|
|
return;
|
|
}
|
|
float num3 = num / (size * (float)num2);
|
|
if (num3 >= 0.5f)
|
|
{
|
|
isOpen = false;
|
|
Open();
|
|
}
|
|
else
|
|
{
|
|
isOpen = true;
|
|
Close();
|
|
}
|
|
}
|
|
|
|
public void OnDrag(PointerEventData eventData)
|
|
{
|
|
if (currentAnimation != null)
|
|
{
|
|
StopCoroutine(currentAnimation);
|
|
}
|
|
Vector2 localPoint;
|
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, eventData.position, eventData.pressEventCamera, out localPoint);
|
|
Vector2 localPoint2;
|
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, eventData.position - eventData.delta, eventData.pressEventCamera, out localPoint2);
|
|
Vector2 vector = localPoint - localPoint2;
|
|
if (Direction == SlideBlockAxis.LeftToRight)
|
|
{
|
|
float x = Mathf.Clamp(RectTransform.anchoredPosition.x + vector.x, closePosition.x, closePosition.x + size);
|
|
RectTransform.anchoredPosition = new Vector2(x, RectTransform.anchoredPosition.y);
|
|
}
|
|
else if (Direction == SlideBlockAxis.RightToLeft)
|
|
{
|
|
float x2 = Mathf.Clamp(RectTransform.anchoredPosition.x + vector.x, closePosition.x - size, closePosition.x);
|
|
RectTransform.anchoredPosition = new Vector2(x2, RectTransform.anchoredPosition.y);
|
|
}
|
|
else if (Direction == SlideBlockAxis.TopToBottom)
|
|
{
|
|
float y = Mathf.Clamp(RectTransform.anchoredPosition.y + vector.y, closePosition.y - size, closePosition.y);
|
|
RectTransform.anchoredPosition = new Vector2(RectTransform.anchoredPosition.x, y);
|
|
}
|
|
else if (Direction == SlideBlockAxis.BottomToTop)
|
|
{
|
|
float y2 = Mathf.Clamp(RectTransform.anchoredPosition.y + vector.y, closePosition.y, closePosition.y + size);
|
|
RectTransform.anchoredPosition = new Vector2(RectTransform.anchoredPosition.x, y2);
|
|
}
|
|
}
|
|
|
|
public void Open()
|
|
{
|
|
if (!IsOpen)
|
|
{
|
|
Animate();
|
|
}
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
if (IsOpen)
|
|
{
|
|
Animate();
|
|
}
|
|
}
|
|
|
|
private bool IsHorizontal()
|
|
{
|
|
return Direction == SlideBlockAxis.LeftToRight || SlideBlockAxis.RightToLeft == Direction;
|
|
}
|
|
|
|
private bool IsReverse()
|
|
{
|
|
return Direction == SlideBlockAxis.RightToLeft || SlideBlockAxis.TopToBottom == Direction;
|
|
}
|
|
|
|
private void Animate()
|
|
{
|
|
if (currentAnimation != null)
|
|
{
|
|
StopCoroutine(currentAnimation);
|
|
}
|
|
float time = Curve.keys[Curve.keys.Length - 1].time;
|
|
size = ((!IsHorizontal()) ? RectTransform.rect.height : RectTransform.rect.width);
|
|
float num = ((!IsHorizontal()) ? RectTransform.anchoredPosition.y : RectTransform.anchoredPosition.x);
|
|
float num2 = num - ((!IsHorizontal()) ? closePosition.y : closePosition.x);
|
|
int num3 = ((!IsReverse()) ? 1 : (-1));
|
|
float num4 = ((!isOpen) ? (size * (float)num3 - num2) : (size * (float)num3));
|
|
float num5 = ((num4 != 0f) ? (size / num4) : 1f);
|
|
if (IsReverse())
|
|
{
|
|
num5 *= -1f;
|
|
}
|
|
currentAnimation = RunAnimation(Time.time, time, num, num4, num5);
|
|
StartCoroutine(currentAnimation);
|
|
}
|
|
|
|
private IEnumerator RunAnimation(float startTime, float animationLength, float startPosition, float movement, float acceleration)
|
|
{
|
|
int direction = ((!isOpen) ? 1 : (-1));
|
|
float delta;
|
|
do
|
|
{
|
|
delta = (Time.time - startTime) * acceleration;
|
|
float value = Curve.Evaluate(delta);
|
|
if (IsHorizontal())
|
|
{
|
|
RectTransform.anchoredPosition = new Vector2(startPosition + value * movement * (float)direction, RectTransform.anchoredPosition.y);
|
|
}
|
|
else
|
|
{
|
|
RectTransform.anchoredPosition = new Vector2(RectTransform.anchoredPosition.x, startPosition + value * movement * (float)direction);
|
|
}
|
|
yield return null;
|
|
}
|
|
while (delta < animationLength);
|
|
isOpen = !isOpen;
|
|
ResetPosition();
|
|
if (IsOpen)
|
|
{
|
|
OnOpen.Invoke();
|
|
}
|
|
else
|
|
{
|
|
OnClose.Invoke();
|
|
}
|
|
}
|
|
}
|
|
}
|