Tanoda
UIScrollToSelection.cs
Go to the documentation of this file.
1
3
4/*USAGE:
5Simply place the script on the ScrollRect that contains the selectable children we'll be scrolling to
6and drag'n'drop the RectTransform of the options "container" that we'll be scrolling.*/
7
8using System.Collections.Generic;
10
12{
13 [RequireComponent(typeof(ScrollRect))]
14 [AddComponentMenu("UI/Extensions/UIScrollToSelection")]
15 public class UIScrollToSelection : MonoBehaviour
16 {
17
18 //*** ATTRIBUTES ***//
19 [Header("[ Settings ]")]
20 [SerializeField]
21 private ScrollType scrollDirection = ScrollType.BOTH;
22 [SerializeField]
23 private float scrollSpeed = 10f;
24
25 [Header("[ Input ]")]
26 [SerializeField]
27 private bool cancelScrollOnInput = false;
28 [SerializeField]
29 private List<KeyCode> cancelScrollKeycodes = new List<KeyCode>();
30
31 //*** PROPERTIES ***//
32 // REFERENCES
33 protected RectTransform LayoutListGroup
34 {
35 get { return TargetScrollRect != null ? TargetScrollRect.content : null; }
36 }
37
38 // SETTINGS
40 {
41 get { return scrollDirection; }
42 }
43 protected float ScrollSpeed
44 {
45 get { return scrollSpeed; }
46 }
47
48 // INPUT
49 protected bool CancelScrollOnInput
50 {
51 get { return cancelScrollOnInput; }
52 }
53 protected List<KeyCode> CancelScrollKeycodes
54 {
55 get { return cancelScrollKeycodes; }
56 }
57
58 // CACHED REFERENCES
59 protected RectTransform ScrollWindow { get; set; }
60 protected ScrollRect TargetScrollRect { get; set; }
61
62 // SCROLLING
63 protected EventSystem CurrentEventSystem
64 {
65 get { return EventSystem.current; }
66 }
67 protected GameObject LastCheckedGameObject { get; set; }
68 protected GameObject CurrentSelectedGameObject
69 {
70 get { return EventSystem.current.currentSelectedGameObject; }
71 }
72 protected RectTransform CurrentTargetRectTransform { get; set; }
73 protected bool IsManualScrollingAvailable { get; set; }
74
75 //*** METHODS - PUBLIC ***//
76
77
78 //*** METHODS - PROTECTED ***//
79 protected virtual void Awake()
80 {
81 TargetScrollRect = GetComponent<ScrollRect>();
82 ScrollWindow = TargetScrollRect.GetComponent<RectTransform>();
83 }
84
85 protected virtual void Start()
86 {
87
88 }
89
90 protected virtual void Update()
91 {
92 UpdateReferences();
93 CheckIfScrollingShouldBeLocked();
94 ScrollRectToLevelSelection();
95 }
96
97 //*** METHODS - PRIVATE ***//
98 private void UpdateReferences()
99 {
100 // update current selected rect transform
102 {
104 CurrentSelectedGameObject.GetComponent<RectTransform>() :
105 null;
106
107 // unlock automatic scrolling
108 if (CurrentSelectedGameObject != null &&
109 CurrentSelectedGameObject.transform.parent == LayoutListGroup.transform)
110 {
112 }
113 }
114
116 }
117
118 private void CheckIfScrollingShouldBeLocked()
119 {
120 if (CancelScrollOnInput == false || IsManualScrollingAvailable == true)
121 {
122 return;
123 }
124
125 for (int i = 0; i < CancelScrollKeycodes.Count; i++)
126 {
127 if (Input.GetKeyDown(CancelScrollKeycodes[i]) == true)
128 {
130
131 break;
132 }
133 }
134 }
135
136 private void ScrollRectToLevelSelection()
137 {
138 // check main references
139 bool referencesAreIncorrect = (TargetScrollRect == null || LayoutListGroup == null || ScrollWindow == null);
140
141 if (referencesAreIncorrect == true || IsManualScrollingAvailable == true)
142 {
143 return;
144 }
145
146 RectTransform selection = CurrentTargetRectTransform;
147
148 // check if scrolling is possible
149 if (selection == null || selection.transform.parent != LayoutListGroup.transform)
150 {
151 return;
152 }
153
154 // depending on selected scroll direction move the scroll rect to selection
155 switch (ScrollDirection)
156 {
157 case ScrollType.VERTICAL:
158 UpdateVerticalScrollPosition(selection);
159 break;
160 case ScrollType.HORIZONTAL:
161 UpdateHorizontalScrollPosition(selection);
162 break;
163 case ScrollType.BOTH:
164 UpdateVerticalScrollPosition(selection);
165 UpdateHorizontalScrollPosition(selection);
166 break;
167 }
168 }
169
170 private void UpdateVerticalScrollPosition(RectTransform selection)
171 {
172 // move the current scroll rect to correct position
173 float selectionPosition = -selection.anchoredPosition.y - (selection.rect.height * (1 - selection.pivot.y));
174
175 float elementHeight = selection.rect.height;
176 float maskHeight = ScrollWindow.rect.height;
177 float listAnchorPosition = LayoutListGroup.anchoredPosition.y;
178
179 // get the element offset value depending on the cursor move direction
180 float offlimitsValue = GetScrollOffset(selectionPosition, listAnchorPosition, elementHeight, maskHeight);
181
182 // move the target scroll rect
183 TargetScrollRect.verticalNormalizedPosition +=
184 (offlimitsValue / LayoutListGroup.rect.height) * Time.unscaledDeltaTime * scrollSpeed;
185 }
186
187 private void UpdateHorizontalScrollPosition(RectTransform selection)
188 {
189 // move the current scroll rect to correct position
190 float selectionPosition = -selection.anchoredPosition.x - (selection.rect.width * (1 - selection.pivot.x));
191
192 float elementWidth = selection.rect.width;
193 float maskWidth = ScrollWindow.rect.width;
194 float listAnchorPosition = -LayoutListGroup.anchoredPosition.x;
195
196 // get the element offset value depending on the cursor move direction
197 float offlimitsValue = -GetScrollOffset(selectionPosition, listAnchorPosition, elementWidth, maskWidth);
198
199 // move the target scroll rect
200 TargetScrollRect.horizontalNormalizedPosition +=
201 (offlimitsValue / LayoutListGroup.rect.width) * Time.unscaledDeltaTime * scrollSpeed;
202 }
203
204 private float GetScrollOffset(float position, float listAnchorPosition, float targetLength, float maskLength)
205 {
206 if (position < listAnchorPosition + (targetLength / 2))
207 {
208 return (listAnchorPosition + maskLength) - (position - targetLength);
209 }
210 else if (position + targetLength > listAnchorPosition + maskLength)
211 {
212 return (listAnchorPosition + maskLength) - (position + targetLength);
213 }
214
215 return 0;
216 }
217
218 //*** ENUMS ***//
219 public enum ScrollType
220 {
221 VERTICAL,
222 HORIZONTAL,
223 BOTH
224 }
225 }
226}
Credit Erdener Gonenc - @PixelEnvision.