2015-12-23 22:54:32 +08:00
|
|
|
|
/// Credit Mrs. YakaYocha
|
|
|
|
|
/// Sourced from - https://www.youtube.com/channel/UCHp8LZ_0-iCvl-5pjHATsgw
|
|
|
|
|
/// Please donate: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RJ8D9FRFQF9VS
|
|
|
|
|
|
|
|
|
|
using UnityEngine.Events;
|
|
|
|
|
|
|
|
|
|
namespace UnityEngine.UI.Extensions
|
|
|
|
|
{
|
|
|
|
|
[RequireComponent(typeof(ScrollRect))]
|
|
|
|
|
[AddComponentMenu("Layout/Extensions/Vertical Scroller")]
|
|
|
|
|
public class UIVerticalScroller : MonoBehaviour
|
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
[Tooltip("desired ScrollRect")]
|
|
|
|
|
public ScrollRect scrollRect;
|
2015-12-23 22:54:32 +08:00
|
|
|
|
[Tooltip("Center display area (position of zoomed content)")]
|
2019-02-23 01:05:03 +08:00
|
|
|
|
public RectTransform center;
|
|
|
|
|
[Tooltip("Size / spacing of elements")]
|
|
|
|
|
public RectTransform elementSize;
|
2020-07-09 03:38:28 +08:00
|
|
|
|
[Tooltip("Scale = 1/ (1+distance from center * shrinkage)")]
|
2019-02-23 01:05:03 +08:00
|
|
|
|
public Vector2 elementShrinkage = new Vector2(1f / 200, 1f / 200);
|
|
|
|
|
[Tooltip("Minimum element scale (furthest from center)")]
|
|
|
|
|
public Vector2 minScale = new Vector2(0.7f, 0.7f);
|
|
|
|
|
[Tooltip("Select the item to be in center on start.")]
|
|
|
|
|
public int startingIndex = -1;
|
|
|
|
|
[Tooltip("Stop scrolling past last element from inertia.")]
|
|
|
|
|
public bool stopMomentumOnEnd = true;
|
|
|
|
|
[Tooltip("Set Items out of center to not interactible.")]
|
|
|
|
|
public bool disableUnfocused = true;
|
2015-12-23 22:54:32 +08:00
|
|
|
|
[Tooltip("Button to go to the next page. (optional)")]
|
2019-02-23 01:05:03 +08:00
|
|
|
|
public GameObject scrollUpButton;
|
2015-12-23 22:54:32 +08:00
|
|
|
|
[Tooltip("Button to go to the previous page. (optional)")]
|
2019-02-23 01:05:03 +08:00
|
|
|
|
public GameObject scrollDownButton;
|
2015-12-23 22:54:32 +08:00
|
|
|
|
[Tooltip("Event fired when a specific item is clicked, exposes index number of item. (optional)")]
|
2019-02-23 01:05:03 +08:00
|
|
|
|
public IntEvent OnButtonClicked;
|
|
|
|
|
[Tooltip("Event fired when the focused item is Changed. (optional)")]
|
|
|
|
|
public IntEvent OnFocusChanged;
|
|
|
|
|
[HideInInspector]
|
|
|
|
|
public GameObject[] _arrayOfElements;
|
2015-12-23 22:54:32 +08:00
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
public int focusedElementIndex { get; private set; }
|
|
|
|
|
|
|
|
|
|
public string result { get; private set; }
|
2015-12-23 22:54:32 +08:00
|
|
|
|
|
|
|
|
|
private float[] distReposition;
|
|
|
|
|
private float[] distance;
|
|
|
|
|
//private int elementsDistance;
|
|
|
|
|
|
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
//Scrollable area (content of desired ScrollRect)
|
|
|
|
|
[HideInInspector]
|
|
|
|
|
public RectTransform scrollingPanel{ get { return scrollRect.content; } }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Constructor when not used as component but called from other script, don't forget to set the non-optional properties.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public UIVerticalScroller()
|
2015-12-23 22:54:32 +08:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Constructor when not used as component but called from other script
|
|
|
|
|
/// </summary>
|
|
|
|
|
public UIVerticalScroller(RectTransform center, RectTransform elementSize, ScrollRect scrollRect, GameObject[] arrayOfElements)
|
|
|
|
|
{
|
|
|
|
|
this.center = center;
|
|
|
|
|
this.elementSize = elementSize;
|
|
|
|
|
this.scrollRect = scrollRect;
|
|
|
|
|
_arrayOfElements = arrayOfElements;
|
|
|
|
|
}
|
2015-12-23 22:54:32 +08:00
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Awake this instance.
|
|
|
|
|
/// </summary>
|
2015-12-23 22:54:32 +08:00
|
|
|
|
public void Awake()
|
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
if (!scrollRect)
|
2015-12-23 22:54:32 +08:00
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
scrollRect = GetComponent<ScrollRect>();
|
2015-12-23 22:54:32 +08:00
|
|
|
|
}
|
2019-02-23 01:05:03 +08:00
|
|
|
|
if (!center)
|
2015-12-23 22:54:32 +08:00
|
|
|
|
{
|
|
|
|
|
Debug.LogError("Please define the RectTransform for the Center viewport of the scrollable area");
|
|
|
|
|
}
|
2019-02-23 01:05:03 +08:00
|
|
|
|
if (!elementSize)
|
|
|
|
|
{
|
|
|
|
|
elementSize = center;
|
|
|
|
|
}
|
2015-12-23 22:54:32 +08:00
|
|
|
|
if (_arrayOfElements == null || _arrayOfElements.Length == 0)
|
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
_arrayOfElements = new GameObject[scrollingPanel.childCount];
|
|
|
|
|
for (int i = 0; i < scrollingPanel.childCount; i++)
|
2015-12-23 22:54:32 +08:00
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
_arrayOfElements[i] = scrollingPanel.GetChild(i).gameObject;
|
|
|
|
|
}
|
2015-12-23 22:54:32 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Recognises and resizes the children.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="startingIndex">Starting index.</param>
|
|
|
|
|
/// <param name="arrayOfElements">Array of elements.</param>
|
|
|
|
|
public void updateChildren(int startingIndex = -1, GameObject[] arrayOfElements = null)
|
2015-12-23 22:54:32 +08:00
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
// Set _arrayOfElements to arrayOfElements if given, otherwise to child objects of the scrolling panel.
|
|
|
|
|
if (arrayOfElements != null)
|
2015-12-23 22:54:32 +08:00
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
_arrayOfElements = arrayOfElements;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_arrayOfElements = new GameObject[scrollingPanel.childCount];
|
|
|
|
|
for (int i = 0; i < scrollingPanel.childCount; i++)
|
|
|
|
|
{
|
|
|
|
|
_arrayOfElements[i] = scrollingPanel.GetChild(i).gameObject;
|
|
|
|
|
}
|
2015-12-23 22:54:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
// resize the elements to match elementSize rect
|
2015-12-23 22:54:32 +08:00
|
|
|
|
for (var i = 0; i < _arrayOfElements.Length; i++)
|
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
int j = i;
|
|
|
|
|
_arrayOfElements[i].GetComponent<Button>().onClick.RemoveAllListeners();
|
|
|
|
|
if (OnButtonClicked != null)
|
|
|
|
|
{
|
|
|
|
|
_arrayOfElements[i].GetComponent<Button>().onClick.AddListener(() => OnButtonClicked.Invoke(j));
|
|
|
|
|
}
|
|
|
|
|
RectTransform r = _arrayOfElements[i].GetComponent<RectTransform>();
|
|
|
|
|
r.anchorMax = r.anchorMin = r.pivot = new Vector2(0.5f, 0.5f);
|
|
|
|
|
r.localPosition = new Vector2(0, i * elementSize.rect.size.y);
|
|
|
|
|
r.sizeDelta = elementSize.rect.size;
|
2015-12-23 22:54:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
// prepare for scrolling
|
|
|
|
|
distance = new float[_arrayOfElements.Length];
|
|
|
|
|
distReposition = new float[_arrayOfElements.Length];
|
|
|
|
|
focusedElementIndex = -1;
|
2015-12-23 22:54:32 +08:00
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
//scrollRect.scrollSensitivity = elementSize.rect.height / 5;
|
2015-12-23 22:54:32 +08:00
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
// if starting index is given, snap to respective element
|
|
|
|
|
if (startingIndex > -1)
|
2015-12-23 22:54:32 +08:00
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
startingIndex = startingIndex > _arrayOfElements.Length ? _arrayOfElements.Length - 1 : startingIndex;
|
|
|
|
|
SnapToElement(startingIndex);
|
2015-12-23 22:54:32 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
public void Start()
|
2015-12-23 22:54:32 +08:00
|
|
|
|
{
|
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
if (scrollUpButton)
|
|
|
|
|
scrollUpButton.GetComponent<Button>().onClick.AddListener(() =>
|
|
|
|
|
{
|
|
|
|
|
ScrollUp();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (scrollDownButton)
|
|
|
|
|
scrollDownButton.GetComponent<Button>().onClick.AddListener(() =>
|
|
|
|
|
{
|
|
|
|
|
ScrollDown();
|
|
|
|
|
});
|
|
|
|
|
updateChildren(startingIndex, _arrayOfElements);
|
2015-12-23 22:54:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
|
2015-12-23 22:54:32 +08:00
|
|
|
|
public void Update()
|
|
|
|
|
{
|
|
|
|
|
if (_arrayOfElements.Length < 1)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
for (var i = 0; i < _arrayOfElements.Length; i++)
|
2015-12-23 22:54:32 +08:00
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
distReposition[i] = center.GetComponent<RectTransform>().position.y - _arrayOfElements[i].GetComponent<RectTransform>().position.y;
|
2015-12-23 22:54:32 +08:00
|
|
|
|
distance[i] = Mathf.Abs(distReposition[i]);
|
|
|
|
|
|
|
|
|
|
//Magnifying effect
|
2019-02-23 01:05:03 +08:00
|
|
|
|
Vector2 scale = Vector2.Max(minScale, new Vector2(1 / (1 + distance[i] * elementShrinkage.x), (1 / (1 + distance[i] * elementShrinkage.y))));
|
|
|
|
|
_arrayOfElements[i].GetComponent<RectTransform>().transform.localScale = new Vector3(scale.x, scale.y, 1f);
|
2015-12-23 22:54:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
// detect focused element
|
|
|
|
|
float minDistance = Mathf.Min(distance);
|
|
|
|
|
int oldFocusedElement = focusedElementIndex;
|
|
|
|
|
for (var i = 0; i < _arrayOfElements.Length; i++)
|
2015-12-23 22:54:32 +08:00
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
_arrayOfElements[i].GetComponent<CanvasGroup>().interactable = !disableUnfocused || minDistance == distance[i];
|
2015-12-23 22:54:32 +08:00
|
|
|
|
if (minDistance == distance[i])
|
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
focusedElementIndex = i;
|
2015-12-23 22:54:32 +08:00
|
|
|
|
result = _arrayOfElements[i].GetComponentInChildren<Text>().text;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-02-23 01:05:03 +08:00
|
|
|
|
if (focusedElementIndex != oldFocusedElement && OnFocusChanged != null)
|
|
|
|
|
{
|
|
|
|
|
OnFocusChanged.Invoke(focusedElementIndex);
|
|
|
|
|
}
|
2015-12-23 22:54:32 +08:00
|
|
|
|
|
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
if (!Input.GetMouseButton(0))
|
|
|
|
|
{
|
|
|
|
|
// scroll slowly to nearest element when not dragged
|
|
|
|
|
ScrollingElements();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// stop scrolling past last element from inertia
|
|
|
|
|
if (stopMomentumOnEnd
|
|
|
|
|
&& (_arrayOfElements[0].GetComponent<RectTransform>().position.y > center.position.y
|
|
|
|
|
|| _arrayOfElements[_arrayOfElements.Length - 1].GetComponent<RectTransform>().position.y < center.position.y))
|
|
|
|
|
{
|
|
|
|
|
scrollRect.velocity = Vector2.zero;
|
|
|
|
|
}
|
2015-12-23 22:54:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-23 01:05:03 +08:00
|
|
|
|
private void ScrollingElements()
|
2015-12-23 22:54:32 +08:00
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
float newY = Mathf.Lerp(scrollingPanel.anchoredPosition.y, scrollingPanel.anchoredPosition.y + distReposition[focusedElementIndex], Time.deltaTime * 2f);
|
|
|
|
|
Vector2 newPosition = new Vector2(scrollingPanel.anchoredPosition.x, newY);
|
|
|
|
|
scrollingPanel.anchoredPosition = newPosition;
|
2015-12-23 22:54:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SnapToElement(int element)
|
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
float deltaElementPositionY = elementSize.rect.height * element;
|
|
|
|
|
Vector2 newPosition = new Vector2(scrollingPanel.anchoredPosition.x, -deltaElementPositionY);
|
|
|
|
|
scrollingPanel.anchoredPosition = newPosition;
|
2015-12-23 22:54:32 +08:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ScrollUp()
|
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
float deltaUp = elementSize.rect.height / 1.2f;
|
|
|
|
|
Vector2 newPositionUp = new Vector2(scrollingPanel.anchoredPosition.x, scrollingPanel.anchoredPosition.y - deltaUp);
|
|
|
|
|
scrollingPanel.anchoredPosition = Vector2.Lerp(scrollingPanel.anchoredPosition, newPositionUp, 1);
|
2015-12-23 22:54:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ScrollDown()
|
|
|
|
|
{
|
2019-02-23 01:05:03 +08:00
|
|
|
|
float deltaDown = elementSize.rect.height / 1.2f;
|
|
|
|
|
Vector2 newPositionDown = new Vector2(scrollingPanel.anchoredPosition.x, scrollingPanel.anchoredPosition.y + deltaDown);
|
|
|
|
|
scrollingPanel.anchoredPosition = newPositionDown;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[System.Serializable]
|
|
|
|
|
public class IntEvent:UnityEvent<int>
|
|
|
|
|
{
|
|
|
|
|
|
2015-12-23 22:54:32 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|