Skip to content

Commit e2f6d1e

Browse files
committed
Add ScrollToSelection script
1 parent c93898f commit e2f6d1e

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed

Runtime/ScrollToSelection.cs

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
using UnityEngine;
2+
using UnityEngine.EventSystems;
3+
using UnityEngine.InputSystem;
4+
using UnityEngine.UI;
5+
6+
namespace Zigurous.UI
7+
{
8+
[RequireComponent(typeof(ScrollRect))]
9+
[AddComponentMenu("Zigurous/UI/Navigation/Scroll To Selection")]
10+
public class ScrollToSelection : MonoBehaviour
11+
{
12+
public enum ScrollDirection
13+
{
14+
Vertical,
15+
Horizontal,
16+
Both,
17+
}
18+
19+
public ScrollDirection scrollDirection;
20+
public float scrollSpeed = 10.0f;
21+
public bool manualScrolling { get; private set; }
22+
23+
public ScrollRect scrollRect { get; private set; }
24+
public RectTransform scrollTransform { get; private set; }
25+
public GameObject selectedGameObject { get; private set; }
26+
public RectTransform selectedTransform { get; private set; }
27+
28+
private void Awake()
29+
{
30+
this.scrollRect = GetComponent<ScrollRect>();
31+
this.scrollTransform = this.scrollRect.GetComponent<RectTransform>();
32+
}
33+
34+
private void Update()
35+
{
36+
CheckForManualScrolling();
37+
SetSelectedGameObject();
38+
SetScrollPosition();
39+
}
40+
41+
private void CheckForManualScrolling()
42+
{
43+
if (Mouse.current != null && Mouse.current.scroll.y.IsActuated()) {
44+
this.manualScrolling = true;
45+
}
46+
}
47+
48+
private void SetSelectedGameObject()
49+
{
50+
EventSystem eventSystem = EventSystem.current;
51+
52+
if (eventSystem == null || eventSystem.currentSelectedGameObject == null) {
53+
return;
54+
}
55+
56+
if (eventSystem.currentSelectedGameObject != this.selectedGameObject &&
57+
eventSystem.currentSelectedGameObject.transform.parent == this.scrollRect.content)
58+
{
59+
this.selectedGameObject = eventSystem.currentSelectedGameObject;
60+
this.selectedTransform = this.selectedGameObject.GetComponent<RectTransform>();
61+
this.manualScrolling = false;
62+
}
63+
}
64+
65+
private void SetScrollPosition()
66+
{
67+
if (this.selectedTransform == null || this.manualScrolling) {
68+
return;
69+
}
70+
71+
switch (this.scrollDirection)
72+
{
73+
case ScrollDirection.Vertical:
74+
ScrollVertical(this.selectedTransform);
75+
break;
76+
77+
case ScrollDirection.Horizontal:
78+
ScrollHorizontal(this.selectedTransform);
79+
break;
80+
81+
case ScrollDirection.Both:
82+
ScrollVertical(this.selectedTransform);
83+
ScrollHorizontal(this.selectedTransform);
84+
break;
85+
}
86+
}
87+
88+
private void ScrollVertical(RectTransform selection)
89+
{
90+
// Calculate the scroll offset
91+
float elementHeight = selection.rect.height;
92+
float maskHeight = this.scrollTransform.rect.height;
93+
float anchorPosition = this.scrollRect.content.anchoredPosition.y;
94+
float selectionPosition = -selection.anchoredPosition.y - (elementHeight * (1.0f - selection.pivot.y));
95+
float offset = GetScrollOffset(selectionPosition, anchorPosition, elementHeight, maskHeight);
96+
97+
// Move the target scroll rect
98+
float position = this.scrollRect.verticalNormalizedPosition;
99+
position = Mathf.Clamp01(position + (offset / this.scrollRect.content.rect.height) * Time.unscaledDeltaTime * this.scrollSpeed);
100+
this.scrollRect.verticalNormalizedPosition = position;
101+
}
102+
103+
private void ScrollHorizontal(RectTransform selection)
104+
{
105+
// Calculate the scroll offset
106+
float selectionPosition = -selection.anchoredPosition.x - (selection.rect.width * (1.0f - selection.pivot.x));
107+
float elementWidth = selection.rect.width;
108+
float maskWidth = this.scrollTransform.rect.width;
109+
float anchorPosition = -this.scrollRect.content.anchoredPosition.x;
110+
float offset = -GetScrollOffset(selectionPosition, anchorPosition, elementWidth, maskWidth);
111+
112+
// Move the target scroll rect
113+
float position = this.scrollRect.horizontalNormalizedPosition;
114+
position = Mathf.Clamp01(position + (offset / this.scrollRect.content.rect.width) * Time.unscaledDeltaTime * this.scrollSpeed);
115+
this.scrollRect.horizontalNormalizedPosition = position;
116+
}
117+
118+
private float GetScrollOffset(float position, float anchorPosition, float targetLength, float maskLength)
119+
{
120+
if (position < anchorPosition + (targetLength * 0.5f)) {
121+
return (anchorPosition + maskLength) - (position - targetLength);
122+
}
123+
else if (position + targetLength > anchorPosition + maskLength) {
124+
return (anchorPosition + maskLength) - (position + targetLength);
125+
}
126+
127+
return 0.0f;
128+
}
129+
130+
}
131+
132+
}

Runtime/ScrollToSelection.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)