199 lines
6.8 KiB
C#
199 lines
6.8 KiB
C#
/// Credit Febo Zodiaco
|
|
/// Sourced from - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/issues/349/magnticinfinitescroll
|
|
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.EventSystems;
|
|
|
|
namespace UnityEngine.UI.Extensions
|
|
{
|
|
[AddComponentMenu("UI/Extensions/UI Magnetic Infinite Scroll")]
|
|
[RequireComponent(typeof(ScrollRect))]
|
|
public class UI_MagneticInfiniteScroll : UI_InfiniteScroll, IDragHandler, IEndDragHandler, IScrollHandler
|
|
{
|
|
public event UnityAction<GameObject> OnNewSelect;
|
|
|
|
[Tooltip("The pointer to the pivot, the visual element for centering objects.")]
|
|
[SerializeField]
|
|
private RectTransform pivot = null;
|
|
[Tooltip("The maximum speed that allows you to activate the magnet to center on the pivot")]
|
|
[SerializeField]
|
|
private float maxSpeedForMagnetic = 10f;
|
|
[SerializeField]
|
|
[Tooltip("The index of the object which must be initially centered")]
|
|
private int indexStart = 0;
|
|
[SerializeField]
|
|
[Tooltip("The time to decelerate and aim to the pivot")]
|
|
private float timeForDeceleration = 0.05f;
|
|
|
|
private float _pastPositionMouseSpeed;
|
|
private float _initMovementDirection = 0;
|
|
private float _pastPosition = 0;
|
|
|
|
private float _currentSpeed = 0.0f;
|
|
private float _stopValue = 0.0f;
|
|
private readonly float _waitForContentSet = 0.1f;
|
|
private float _currentTime = 0;
|
|
private int _nearestIndex = 0;
|
|
|
|
private bool _useMagnetic = true;
|
|
private bool _isStopping = false;
|
|
private bool _isMovement = false;
|
|
|
|
public List<RectTransform> Items { get; }
|
|
|
|
protected override void Awake()
|
|
{
|
|
base.Awake();
|
|
StartCoroutine(SetInitContent());
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (_scrollRect == null || !_scrollRect.content || !pivot || !_useMagnetic || !_isMovement || items == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
float currentPosition = GetRightAxis(_scrollRect.content.anchoredPosition);
|
|
_currentSpeed = Mathf.Abs(currentPosition - _pastPosition);
|
|
_pastPosition = currentPosition;
|
|
if (Mathf.Abs(_currentSpeed) > maxSpeedForMagnetic)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_isStopping)
|
|
{
|
|
Vector2 anchoredPosition = _scrollRect.content.anchoredPosition;
|
|
_currentTime += Time.deltaTime;
|
|
float valueLerp = _currentTime / timeForDeceleration;
|
|
|
|
float newPosition = Mathf.Lerp(GetRightAxis(anchoredPosition), _stopValue, valueLerp);
|
|
|
|
_scrollRect.content.anchoredPosition = _isVertical ? new Vector2(anchoredPosition.x, newPosition) :
|
|
new Vector2(newPosition, anchoredPosition.y);
|
|
|
|
|
|
if (newPosition == GetRightAxis(anchoredPosition) && _nearestIndex > 0 && _nearestIndex < items.Count)
|
|
{
|
|
_isStopping = false;
|
|
_isMovement = false;
|
|
var item = items[_nearestIndex];
|
|
if (item != null && OnNewSelect != null)
|
|
{
|
|
|
|
OnNewSelect.Invoke(item.gameObject);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
float distance = Mathf.Infinity * (-_initMovementDirection);
|
|
|
|
for (int i = 0; i < items.Count; i++)
|
|
{
|
|
var item = items[i];
|
|
if (item == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var aux = GetRightAxis(item.position) - GetRightAxis(pivot.position);
|
|
|
|
if ((_initMovementDirection <= 0 && aux < distance && aux > 0) ||
|
|
(_initMovementDirection > 0 && aux > distance && aux < 0))
|
|
{
|
|
distance = aux;
|
|
_nearestIndex = i;
|
|
}
|
|
}
|
|
|
|
_isStopping = true;
|
|
_stopValue = GetAnchoredPositionForPivot(_nearestIndex);
|
|
_scrollRect.StopMovement();
|
|
}
|
|
}
|
|
|
|
public override void SetNewItems(ref List<Transform> newItems)
|
|
{
|
|
foreach (var element in newItems)
|
|
{
|
|
RectTransform rectTransform = element.GetComponent<RectTransform>();
|
|
if (rectTransform && pivot)
|
|
{
|
|
rectTransform.sizeDelta = pivot.sizeDelta;
|
|
}
|
|
}
|
|
base.SetNewItems(ref newItems);
|
|
}
|
|
|
|
public void SetContentInPivot(int index)
|
|
{
|
|
float newPos = GetAnchoredPositionForPivot(index);
|
|
Vector2 anchoredPosition = _scrollRect.content.anchoredPosition;
|
|
|
|
if (_scrollRect.content)
|
|
{
|
|
_scrollRect.content.anchoredPosition = _isVertical ? new Vector2(anchoredPosition.x, newPos) :
|
|
new Vector2(newPos, anchoredPosition.y);
|
|
_pastPosition = GetRightAxis(_scrollRect.content.anchoredPosition);
|
|
}
|
|
}
|
|
|
|
private IEnumerator SetInitContent()
|
|
{
|
|
yield return new WaitForSeconds(_waitForContentSet);
|
|
SetContentInPivot(indexStart);
|
|
}
|
|
|
|
private float GetAnchoredPositionForPivot(int index)
|
|
{
|
|
if (!pivot || items == null || items.Count < 0)
|
|
{
|
|
return 0f;
|
|
}
|
|
|
|
index = Mathf.Clamp(index, 0, items.Count - 1);
|
|
|
|
float posItem = GetRightAxis(items[index].anchoredPosition);
|
|
float posPivot = GetRightAxis(pivot.anchoredPosition);
|
|
return posPivot - posItem;
|
|
}
|
|
|
|
private void FinishPrepareMovement()
|
|
{
|
|
_isMovement = true;
|
|
_useMagnetic = true;
|
|
_isStopping = false;
|
|
_currentTime = 0;
|
|
}
|
|
|
|
private float GetRightAxis(Vector2 vector)
|
|
{
|
|
return _isVertical ? vector.y : vector.x;
|
|
}
|
|
|
|
public void OnDrag(PointerEventData eventData)
|
|
{
|
|
float currentPosition = GetRightAxis(UIExtensionsInputManager.MousePosition);
|
|
|
|
_initMovementDirection = Mathf.Sign(currentPosition - _pastPositionMouseSpeed);
|
|
_pastPositionMouseSpeed = currentPosition;
|
|
_useMagnetic = false;
|
|
_isStopping = false;
|
|
}
|
|
|
|
public void OnEndDrag(PointerEventData eventData)
|
|
{
|
|
FinishPrepareMovement();
|
|
}
|
|
|
|
public void OnScroll(PointerEventData eventData)
|
|
{
|
|
_initMovementDirection = -UIExtensionsInputManager.MouseScrollDelta.y;
|
|
FinishPrepareMovement();
|
|
}
|
|
}
|
|
} |