天津23维预案
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

460 lines
11 KiB

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using System.Collections;
namespace UIWidgets {
/// <summary>
/// SlideBlock axis.
/// </summary>
public enum SlideBlockAxis
{
LeftToRight = 0,
TopToBottom = 1,
RightToLeft = 2,
BottomToTop = 3,
}
/// <summary>
/// SlideBlock.
/// </summary>
[AddComponentMenu("UI/UIWidgets/SlideBlock")]
public class SlideBlock : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler {
/// <summary>
/// AnimationCurve.
/// </summary>
[SerializeField]
[Tooltip("Requirements: start value should be less than end value; Recommended start value = 0; end value = 1;")]
public AnimationCurve Curve = AnimationCurve.EaseInOut(0, 0, 1, 1);
/// <summary>
/// Direction.
/// </summary>
public SlideBlockAxis Direction = SlideBlockAxis.LeftToRight;
[SerializeField]
bool isOpen;
/// <summary>
/// Gets or sets a value indicating whether this instance is open.
/// </summary>
/// <value><c>true</c> if this instance is open; otherwise, <c>false</c>.</value>
public bool IsOpen {
get {
return isOpen;
}
set {
isOpen = value;
ResetPosition();
}
}
[SerializeField]
bool scrollRectSupport;
/// <summary>
/// Process children ScrollRect's drag events.
/// </summary>
/// <value><c>true</c> if scroll rect support; otherwise, <c>false</c>.</value>
public bool ScrollRectSupport {
get {
return scrollRectSupport;
}
set {
if (scrollRectSupport)
{
GetComponentsInChildren<ScrollRect>().ForEach(RemoveHandleEvents);
}
scrollRectSupport = value;
if (scrollRectSupport)
{
GetComponentsInChildren<ScrollRect>().ForEach(AddHandleEvents);
}
}
}
[SerializeField]
GameObject optionalHandle;
/// <summary>
/// Gets or sets the optional handle.
/// </summary>
/// <value>The optional handle.</value>
public GameObject OptionalHandle {
get {
return optionalHandle;
}
set {
if (optionalHandle!=null)
{
RemoveHandleEvents(optionalHandle);
}
optionalHandle = value;
if (optionalHandle!=null)
{
AddHandleEvents(optionalHandle);
}
}
}
/// <summary>
/// Use unscaled time.
/// </summary>
[SerializeField]
public bool UnscaledTime = false;
/// <summary>
/// OnOpen event.
/// </summary>
public UnityEvent OnOpen = new UnityEvent();
/// <summary>
/// OnClose event.
/// </summary>
public UnityEvent OnClose = new UnityEvent();
RectTransform rectTransform;
/// <summary>
/// Gets the RectTransform.
/// </summary>
/// <value>RectTransform.</value>
protected RectTransform RectTransform {
get {
if (rectTransform==null)
{
rectTransform = transform as RectTransform;
}
return rectTransform;
}
}
/// <summary>
/// Position on Start().
/// </summary>
Vector2 closePosition;
/// <summary>
/// The current animation.
/// </summary>
IEnumerator currentAnimation;
float size;
string GetWarning()
{
var 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;
}
void Start()
{
var warning = GetWarning();
if (warning!=string.Empty)
{
Debug.LogWarning(warning, this);
}
closePosition = RectTransform.anchoredPosition;
size = (IsHorizontal()) ? RectTransform.rect.width : RectTransform.rect.height;
if (IsOpen)
{
if (SlideBlockAxis.LeftToRight==Direction)
{
closePosition = new Vector2(closePosition.x - size, closePosition.y);
}
if (SlideBlockAxis.RightToLeft==Direction)
{
closePosition = new Vector2(closePosition.x + size, closePosition.y);
}
else if (SlideBlockAxis.TopToBottom==Direction)
{
closePosition = new Vector2(closePosition.x, closePosition.y - size);
}
else if (SlideBlockAxis.BottomToTop==Direction)
{
closePosition = new Vector2(closePosition.x, closePosition.y + size);
}
}
OptionalHandle = optionalHandle;
ScrollRectSupport = scrollRectSupport;
}
void AddScrollRectHandle()
{
GetComponentsInChildren<ScrollRect>().ForEach(AddHandleEvents);
}
void RemoveScrollRectHandle()
{
GetComponentsInChildren<ScrollRect>().ForEach(RemoveHandleEvents);
}
void AddHandleEvents(Component handleComponent)
{
AddHandleEvents(handleComponent.gameObject);
}
void AddHandleEvents(GameObject handleObject)
{
var handle = handleObject.GetComponent<SlideBlockHandle>();
if (handle==null)
{
handle = handleObject.AddComponent<SlideBlockHandle>();
}
handle.BeginDragEvent.AddListener(OnBeginDrag);
handle.DragEvent.AddListener(OnDrag);
handle.EndDragEvent.AddListener(OnEndDrag);
}
void RemoveHandleEvents(Component handleComponent)
{
RemoveHandleEvents(handleComponent.gameObject);
}
void RemoveHandleEvents(GameObject handleObject)
{
var handle = handleObject.GetComponent<SlideBlockHandle>();
if (handle!=null)
{
handle.BeginDragEvent.RemoveListener(OnBeginDrag);
handle.DragEvent.RemoveListener(OnDrag);
handle.EndDragEvent.RemoveListener(OnEndDrag);
}
}
void ResetPosition()
{
if (isOpen)
{
size = (IsHorizontal()) ? RectTransform.rect.width : RectTransform.rect.height;
if (SlideBlockAxis.LeftToRight==Direction)
{
RectTransform.anchoredPosition = new Vector2(closePosition.x + size, RectTransform.anchoredPosition.y);
}
else if (SlideBlockAxis.RightToLeft==Direction)
{
RectTransform.anchoredPosition = new Vector2(closePosition.x - size, RectTransform.anchoredPosition.y);
}
else if (SlideBlockAxis.TopToBottom==Direction)
{
RectTransform.anchoredPosition = new Vector2(RectTransform.anchoredPosition.x, closePosition.y - size);
}
else if (SlideBlockAxis.BottomToTop==Direction)
{
RectTransform.anchoredPosition = new Vector2(RectTransform.anchoredPosition.x, closePosition.y + size);
}
}
else
{
RectTransform.anchoredPosition = closePosition;
}
}
/// <summary>
/// Toggle this instance.
/// </summary>
public void Toggle()
{
if (IsOpen)
{
Close();
}
else
{
Open();
}
}
/// <summary>
/// Called by a BaseInputModule before a drag is started.
/// </summary>
/// <param name="eventData">Event data.</param>
public void OnBeginDrag(PointerEventData eventData)
{
size = (IsHorizontal()) ? RectTransform.rect.width : RectTransform.rect.height;
}
/// <summary>
/// Called by a BaseInputModule when a drag is ended.
/// </summary>
/// <param name="eventData">Event data.</param>
public void OnEndDrag(PointerEventData eventData)
{
var pos = (IsHorizontal())
? RectTransform.anchoredPosition.x - closePosition.x
: RectTransform.anchoredPosition.y - closePosition.y;
if (pos==0f)
{
isOpen = false;
OnClose.Invoke();
return ;
}
var sign = IsReverse() ? -1 : +1;
if (pos==(size * sign))
{
isOpen = true;
OnOpen.Invoke();
return ;
}
var k = pos / (size * sign);
if (k >= 0.5f)
{
isOpen = false;
Open();
}
else
{
isOpen = true;
Close();
}
}
/// <summary>
/// When draging is occuring this will be called every time the cursor is moved.
/// </summary>
/// <param name="eventData">Event data.</param>
public void OnDrag(PointerEventData eventData)
{
if (currentAnimation!=null)
{
StopCoroutine(currentAnimation);
}
Vector2 p1;
RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, eventData.position, eventData.pressEventCamera, out p1);
Vector2 p2;
RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, eventData.position - eventData.delta, eventData.pressEventCamera, out p2);
var delta = p1 - p2;
if (SlideBlockAxis.LeftToRight==Direction)
{
var x = Mathf.Clamp(RectTransform.anchoredPosition.x + delta.x, closePosition.x, closePosition.x + size);
RectTransform.anchoredPosition = new Vector2(x, RectTransform.anchoredPosition.y);
}
else if (SlideBlockAxis.RightToLeft==Direction)
{
var x = Mathf.Clamp(RectTransform.anchoredPosition.x + delta.x, closePosition.x - size, closePosition.x);
RectTransform.anchoredPosition = new Vector2(x, RectTransform.anchoredPosition.y);
}
else if (SlideBlockAxis.TopToBottom==Direction)
{
var y = Mathf.Clamp(RectTransform.anchoredPosition.y + delta.y, closePosition.y - size, closePosition.y);
RectTransform.anchoredPosition = new Vector2(RectTransform.anchoredPosition.x, y);
}
else if (SlideBlockAxis.BottomToTop==Direction)
{
var y = Mathf.Clamp(RectTransform.anchoredPosition.y + delta.y, closePosition.y, closePosition.y + size);
RectTransform.anchoredPosition = new Vector2(RectTransform.anchoredPosition.x, y);
}
}
/// <summary>
/// Open this instance.
/// </summary>
public void Open()
{
if (IsOpen)
{
return ;
}
Animate();
}
/// <summary>
/// Close this instance.
/// </summary>
public void Close()
{
if (!IsOpen)
{
return ;
}
Animate();
}
bool IsHorizontal()
{
return SlideBlockAxis.LeftToRight==Direction || SlideBlockAxis.RightToLeft==Direction;
}
bool IsReverse()
{
return SlideBlockAxis.RightToLeft==Direction || SlideBlockAxis.TopToBottom==Direction;
}
void Animate()
{
if (currentAnimation!=null)
{
StopCoroutine(currentAnimation);
}
var animationLength = Curve.keys[Curve.keys.Length - 1].time;
size = IsHorizontal() ? RectTransform.rect.width : RectTransform.rect.height;
var startPosition = IsHorizontal() ? RectTransform.anchoredPosition.x : RectTransform.anchoredPosition.y;
var pos = startPosition - (IsHorizontal() ? closePosition.x : closePosition.y);
var sign = IsReverse() ? -1 : +1;
var movement = isOpen ? (size*sign) : (size * sign) - pos;
var acceleration = (movement==0f) ? 1f : size / movement;
if (IsReverse())
{
acceleration *= -1;
}
currentAnimation = RunAnimation(animationLength, startPosition, movement, acceleration);
StartCoroutine(currentAnimation);
}
IEnumerator RunAnimation(float animationLength, float startPosition, float movement, float acceleration)
{
float delta;
var direction = isOpen ? -1 : +1;
var startTime = (UnscaledTime ? Time.unscaledTime : Time.time);
do
{
delta = ((UnscaledTime ? Time.unscaledTime : Time.time) - startTime) * acceleration;
var value = Curve.Evaluate(delta);
if (IsHorizontal())
{
RectTransform.anchoredPosition = new Vector2(startPosition + (value * movement * direction), RectTransform.anchoredPosition.y);
}
else
{
RectTransform.anchoredPosition = new Vector2(RectTransform.anchoredPosition.x, startPosition + (value * movement * direction));
}
yield return null;
}
while (delta < animationLength);
isOpen = !isOpen;
ResetPosition();
if (IsOpen)
{
OnOpen.Invoke();
}
else
{
OnClose.Invoke();
}
}
}
}