Skip to content
This repository was archived by the owner on Mar 20, 2023. It is now read-only.

Commit 37fa5da

Browse files
Adding new magnetic scroll control
Includes some fix updates to the Infinite scroll for content of various sizes
1 parent dbd3bcb commit 37fa5da

File tree

5 files changed

+278
-14
lines changed

5 files changed

+278
-14
lines changed

Examples~

Submodule Examples~ updated from a8ce2ee to 9d756f7

Runtime/Scripts/Utilities/UIExtensionsInputManager.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,18 @@ public static Vector3 MousePosition
273273
return Input.mousePosition;
274274
#else
275275
return Mouse.current.position.ReadValue();
276+
#endif
277+
}
278+
}
279+
280+
public static Vector3 MouseScrollDelta
281+
{
282+
get
283+
{
284+
#if ENABLE_LEGACY_INPUT_MANAGER
285+
return Input.mouseScrollDelta;
286+
#else
287+
return Mouse.current.position.ReadValue();
276288
#endif
277289
}
278290
}

Runtime/Scripts/Utilities/UI_InfiniteScroll.cs

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/// Credit Tomasz Schelenz
22
/// Sourced from - https://bitbucket.org/SimonDarksideJ/unity-ui-extensions/issues/81/infinite-scrollrect
33
/// Demo - https://www.youtube.com/watch?v=uVTV7Udx78k - configures automatically. - works in both vertical and horizontal (but not both at the same time) - drag and drop - can be initialized by code (in case you populate your scrollview content from code)
4+
/// Updated by Febo Zodiaco - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/issues/349/magnticinfinitescroll
45

56
using System.Collections.Generic;
67

@@ -11,10 +12,10 @@ namespace UnityEngine.UI.Extensions
1112
///
1213
/// Fields
1314
/// - InitByUSer - in case your scrollrect is populated from code, you can explicitly Initialize the infinite scroll after your scroll is ready
14-
/// by callin Init() method
15+
/// by calling Init() method
1516
///
1617
/// Notes
17-
/// - doesn't work in both vertical and horizontal orientation at the same time.
18+
/// - does not work in both vertical and horizontal orientation at the same time.
1819
/// - in order to work it disables layout components and size fitter if present(automatically)
1920
///
2021
/// </summary>
@@ -29,25 +30,65 @@ public class UI_InfiniteScroll : MonoBehaviour
2930
private VerticalLayoutGroup _verticalLayoutGroup;
3031
private HorizontalLayoutGroup _horizontalLayoutGroup;
3132
private GridLayoutGroup _gridLayoutGroup;
32-
private bool _isVertical = false;
33-
private bool _isHorizontal = false;
33+
protected bool _isVertical = false;
34+
protected bool _isHorizontal = false;
3435
private float _disableMarginX = 0;
3536
private float _disableMarginY = 0;
3637
private bool _hasDisabledGridComponents = false;
37-
private List<RectTransform> items = new List<RectTransform>();
38+
protected List<RectTransform> items = new List<RectTransform>();
3839
private Vector2 _newAnchoredPosition = Vector2.zero;
3940
//TO DISABLE FLICKERING OBJECT WHEN SCROLL VIEW IS IDLE IN BETWEEN OBJECTS
4041
private float _treshold = 100f;
4142
private int _itemCount = 0;
4243
private float _recordOffsetX = 0;
4344
private float _recordOffsetY = 0;
4445

45-
void Awake()
46+
protected virtual void Awake()
4647
{
4748
if (!InitByUser)
4849
Init();
4950
}
5051

52+
public virtual void SetNewItems(ref List<Transform> newItems)
53+
{
54+
if (_scrollRect != null)
55+
{
56+
if (_scrollRect.content == null && newItems == null)
57+
{
58+
return;
59+
}
60+
61+
if (items != null)
62+
{
63+
items.Clear();
64+
}
65+
66+
for (int i = _scrollRect.content.childCount - 1; i >= 0; i--)
67+
{
68+
Transform child = _scrollRect.content.GetChild(i);
69+
child.SetParent(null);
70+
GameObject.DestroyImmediate(child.gameObject);
71+
}
72+
73+
foreach (Transform newItem in newItems)
74+
{
75+
newItem.SetParent(_scrollRect.content);
76+
}
77+
78+
SetItems();
79+
}
80+
}
81+
82+
private void SetItems()
83+
{
84+
for (int i = 0; i < _scrollRect.content.childCount; i++)
85+
{
86+
items.Add(_scrollRect.content.GetChild(i).GetComponent<RectTransform>());
87+
}
88+
89+
_itemCount = _scrollRect.content.childCount;
90+
}
91+
5192
public void Init()
5293
{
5394
if (GetComponent<ScrollRect>() != null)
@@ -56,10 +97,6 @@ public void Init()
5697
_scrollRect.onValueChanged.AddListener(OnScroll);
5798
_scrollRect.movementType = ScrollRect.MovementType.Unrestricted;
5899

59-
for (int i = 0; i < _scrollRect.content.childCount; i++)
60-
{
61-
items.Add(_scrollRect.content.GetChild(i).GetComponent<RectTransform>());
62-
}
63100
if (_scrollRect.content.GetComponent<VerticalLayoutGroup>() != null)
64101
{
65102
_verticalLayoutGroup = _scrollRect.content.GetComponent<VerticalLayoutGroup>();
@@ -85,7 +122,7 @@ public void Init()
85122
Debug.LogError("UI_InfiniteScroll doesn't support scrolling in both directions, please choose one direction (horizontal or vertical)");
86123
}
87124

88-
_itemCount = _scrollRect.content.childCount;
125+
SetItems();
89126
}
90127
else
91128
{
@@ -102,7 +139,7 @@ void DisableGridComponents()
102139
{
103140
_recordOffsetY *= -1;
104141
}
105-
_disableMarginY = _recordOffsetY * _itemCount / 2;// _scrollRect.GetComponent<RectTransform>().rect.height/2 + items[0].sizeDelta.y;
142+
_disableMarginY = _recordOffsetY * _itemCount / 2;
106143
}
107144
if (_isHorizontal)
108145
{
@@ -111,7 +148,7 @@ void DisableGridComponents()
111148
{
112149
_recordOffsetX *= -1;
113150
}
114-
_disableMarginX = _recordOffsetX * _itemCount / 2;//_scrollRect.GetComponent<RectTransform>().rect.width/2 + items[0].sizeDelta.x;
151+
_disableMarginX = _recordOffsetX * _itemCount / 2;
115152
}
116153

117154
if (_verticalLayoutGroup)
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/// Credit Febo Zodiaco
2+
/// Sourced from - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/issues/349/magnticinfinitescroll
3+
///
4+
5+
using System;
6+
using System.Collections;
7+
using System.Collections.Generic;
8+
9+
namespace UnityEngine.UI.Extensions
10+
{
11+
[AddComponentMenu("UI/Extensions/UI Magnetic Infinite Scroll")]
12+
public class UI_MagneticInfiniteScroll : UI_InfiniteScroll
13+
{
14+
public event Action<GameObject> OnNewSelect;
15+
16+
[Tooltip("The pointer to the pivot, the visual element for centering objects.")]
17+
[SerializeField]
18+
private RectTransform pivot = null;
19+
[Tooltip("The pointer to the object container")]
20+
[SerializeField]
21+
private RectTransform content = null;
22+
[Tooltip("the maximum speed that allows you to activate the magnet to center on the pivot")]
23+
[SerializeField]
24+
private float maxSpeedForMagnetic = 10f;
25+
[SerializeField]
26+
[Tooltip("The initial index of the object which must be initially centered")]
27+
private int indexStart = 0;
28+
[SerializeField]
29+
[Tooltip("The time to decelerate and aim for the pivot")]
30+
private float timeForDeceleration = 0.05f;
31+
32+
[SerializeField]
33+
private ScrollRect scrollRect = null;
34+
35+
private float _pastPositionMouseSpeed;
36+
private float initMovementDirection = 0;
37+
private float _pastPosition = 0;
38+
39+
private float _currentSpeed = 0.0f;
40+
private float _stopValue = 0.0f;
41+
private readonly float _waitForContentSet = 0.1f;
42+
private float _currentTime = 0;
43+
private int nearestIndex = 0;
44+
45+
private bool _useMagnetic = true;
46+
private bool _isStopping = false;
47+
private bool _isMovement = false;
48+
49+
public List<RectTransform> Items { get; }
50+
51+
protected override void Awake()
52+
{
53+
base.Awake();
54+
StartCoroutine(SetInitContent());
55+
}
56+
57+
private void Update()
58+
{
59+
if (!content || !pivot || !_useMagnetic || !_isMovement || items == null || scrollRect == null)
60+
{
61+
return;
62+
}
63+
64+
float currentPosition = GetRightAxis(content.anchoredPosition);
65+
_currentSpeed = Mathf.Abs(currentPosition - _pastPosition);
66+
_pastPosition = currentPosition;
67+
if (Mathf.Abs(_currentSpeed) > maxSpeedForMagnetic)
68+
{
69+
return;
70+
}
71+
72+
if (_isStopping)
73+
{
74+
Vector2 anchoredPosition = content.anchoredPosition;
75+
_currentTime += Time.deltaTime;
76+
float valueLerp = _currentTime / timeForDeceleration;
77+
78+
float newPosition = Mathf.Lerp(GetRightAxis(anchoredPosition), _stopValue, valueLerp);
79+
80+
content.anchoredPosition = _isVertical ? new Vector2(anchoredPosition.x, newPosition) :
81+
new Vector2(newPosition, anchoredPosition.y);
82+
83+
84+
if (newPosition == GetRightAxis(anchoredPosition) && nearestIndex > 0 && nearestIndex < items.Count)
85+
{
86+
_isStopping = false;
87+
_isMovement = false;
88+
var item = items[nearestIndex];
89+
if (item != null && OnNewSelect != null)
90+
{
91+
92+
OnNewSelect.Invoke(item.gameObject);
93+
}
94+
}
95+
}
96+
else
97+
{
98+
float distance = Mathf.Infinity * (-initMovementDirection);
99+
100+
for (int i = 0; i < items.Count; i++)
101+
{
102+
var item = items[i];
103+
if (item == null)
104+
{
105+
continue;
106+
}
107+
108+
var aux = GetRightAxis(item.position) - GetRightAxis(pivot.position);
109+
110+
if ((initMovementDirection <= 0 && aux < distance && aux > 0) ||
111+
(initMovementDirection > 0 && aux > distance && aux < 0))
112+
{
113+
distance = aux;
114+
nearestIndex = i;
115+
}
116+
}
117+
118+
_isStopping = true;
119+
_stopValue = GetAnchoredPositionForPivot(nearestIndex);
120+
scrollRect.StopMovement();
121+
}
122+
}
123+
124+
public void Drag()
125+
{
126+
float currentPosition = GetRightAxis(UIExtensionsInputManager.MousePosition);
127+
128+
initMovementDirection = Mathf.Sign(currentPosition - _pastPositionMouseSpeed);
129+
_pastPositionMouseSpeed = currentPosition;
130+
_useMagnetic = false;
131+
_isStopping = false;
132+
}
133+
134+
public void EndDrag()
135+
{
136+
FinishPrepareMovement();
137+
}
138+
139+
public override void SetNewItems(ref List<Transform> newItems)
140+
{
141+
foreach (var element in newItems)
142+
{
143+
RectTransform rectTransform = element.GetComponent<RectTransform>();
144+
if (rectTransform && pivot)
145+
{
146+
rectTransform.sizeDelta = pivot.sizeDelta;
147+
}
148+
}
149+
base.SetNewItems(ref newItems);
150+
}
151+
152+
public void Scroll()
153+
{
154+
initMovementDirection = -UIExtensionsInputManager.MouseScrollDelta.y;
155+
FinishPrepareMovement();
156+
}
157+
158+
public void SetContentInPivot(int index)
159+
{
160+
float newPos = GetAnchoredPositionForPivot(index);
161+
Vector2 anchoredPosition = content.anchoredPosition;
162+
163+
if (content)
164+
{
165+
content.anchoredPosition = _isVertical ? new Vector2(anchoredPosition.x, newPos) :
166+
new Vector2(newPos, anchoredPosition.y);
167+
_pastPosition = GetRightAxis(content.anchoredPosition);
168+
}
169+
}
170+
171+
private IEnumerator SetInitContent()
172+
{
173+
yield return new WaitForSeconds(_waitForContentSet);
174+
SetContentInPivot(indexStart);
175+
}
176+
177+
private float GetAnchoredPositionForPivot(int index)
178+
{
179+
if (!pivot || items == null || items.Count < 0)
180+
{
181+
return 0f;
182+
}
183+
184+
index = Mathf.Clamp(index, 0, items.Count - 1);
185+
186+
float posItem = GetRightAxis(items[index].anchoredPosition);
187+
float posPivot = GetRightAxis(pivot.anchoredPosition);
188+
return posPivot - posItem;
189+
}
190+
191+
private void FinishPrepareMovement()
192+
{
193+
_isMovement = true;
194+
_useMagnetic = true;
195+
_isStopping = false;
196+
_currentTime = 0;
197+
}
198+
199+
private float GetRightAxis(Vector2 vector)
200+
{
201+
return _isVertical ? vector.y : vector.x;
202+
}
203+
}
204+
}

Runtime/Scripts/Utilities/UI_MagneticInfiniteScroll.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)