UI_InfiniteScroll.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /// Credit Tomasz Schelenz
  2. /// Sourced from - https://bitbucket.org/SimonDarksideJ/unity-ui-extensions/issues/81/infinite-scrollrect
  3. /// 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
  5. using System.Collections.Generic;
  6. namespace UnityEngine.UI.Extensions
  7. {
  8. /// <summary>
  9. /// Infinite scroll view with automatic configuration
  10. ///
  11. /// Fields
  12. /// - InitByUSer - in case your scrollrect is populated from code, you can explicitly Initialize the infinite scroll after your scroll is ready
  13. /// by calling Init() method
  14. ///
  15. /// Notes
  16. /// - does not work in both vertical and horizontal orientation at the same time.
  17. /// - in order to work it disables layout components and size fitter if present(automatically)
  18. ///
  19. /// </summary>
  20. [AddComponentMenu("UI/Extensions/UI Infinite Scroll")]
  21. public class UI_InfiniteScroll : MonoBehaviour
  22. {
  23. //if true user will need to call Init() method manually (in case the contend of the scrollview is generated from code or requires special initialization)
  24. [Tooltip("If false, will Init automatically, otherwise you need to call Init() method")]
  25. public bool InitByUser = false;
  26. protected ScrollRect _scrollRect;
  27. private ContentSizeFitter _contentSizeFitter;
  28. private VerticalLayoutGroup _verticalLayoutGroup;
  29. private HorizontalLayoutGroup _horizontalLayoutGroup;
  30. private GridLayoutGroup _gridLayoutGroup;
  31. protected bool _isVertical = false;
  32. protected bool _isHorizontal = false;
  33. private float _disableMarginX = 0;
  34. private float _disableMarginY = 0;
  35. private bool _hasDisabledGridComponents = false;
  36. protected List<RectTransform> items = new List<RectTransform>();
  37. private Vector2 _newAnchoredPosition = Vector2.zero;
  38. //TO DISABLE FLICKERING OBJECT WHEN SCROLL VIEW IS IDLE IN BETWEEN OBJECTS
  39. private float _threshold = 100f;
  40. private int _itemCount = 0;
  41. private float _recordOffsetX = 0;
  42. private float _recordOffsetY = 0;
  43. protected virtual void Awake()
  44. {
  45. if (!InitByUser)
  46. Init();
  47. }
  48. public virtual void SetNewItems(ref List<Transform> newItems)
  49. {
  50. if (_scrollRect != null)
  51. {
  52. if (_scrollRect.content == null && newItems == null)
  53. {
  54. return;
  55. }
  56. if (items != null)
  57. {
  58. items.Clear();
  59. }
  60. for (int i = _scrollRect.content.childCount - 1; i >= 0; i--)
  61. {
  62. Transform child = _scrollRect.content.GetChild(i);
  63. child.SetParent(null);
  64. GameObject.DestroyImmediate(child.gameObject);
  65. }
  66. foreach (Transform newItem in newItems)
  67. {
  68. newItem.SetParent(_scrollRect.content);
  69. }
  70. SetItems();
  71. }
  72. }
  73. private void SetItems()
  74. {
  75. for (int i = 0; i < _scrollRect.content.childCount; i++)
  76. {
  77. items.Add(_scrollRect.content.GetChild(i).GetComponent<RectTransform>());
  78. }
  79. _itemCount = _scrollRect.content.childCount;
  80. }
  81. public void Init()
  82. {
  83. if (GetComponent<ScrollRect>() != null)
  84. {
  85. _scrollRect = GetComponent<ScrollRect>();
  86. _scrollRect.onValueChanged.AddListener(OnScroll);
  87. _scrollRect.movementType = ScrollRect.MovementType.Unrestricted;
  88. if (_scrollRect.content.GetComponent<VerticalLayoutGroup>() != null)
  89. {
  90. _verticalLayoutGroup = _scrollRect.content.GetComponent<VerticalLayoutGroup>();
  91. }
  92. if (_scrollRect.content.GetComponent<HorizontalLayoutGroup>() != null)
  93. {
  94. _horizontalLayoutGroup = _scrollRect.content.GetComponent<HorizontalLayoutGroup>();
  95. }
  96. if (_scrollRect.content.GetComponent<GridLayoutGroup>() != null)
  97. {
  98. _gridLayoutGroup = _scrollRect.content.GetComponent<GridLayoutGroup>();
  99. }
  100. if (_scrollRect.content.GetComponent<ContentSizeFitter>() != null)
  101. {
  102. _contentSizeFitter = _scrollRect.content.GetComponent<ContentSizeFitter>();
  103. }
  104. _isHorizontal = _scrollRect.horizontal;
  105. _isVertical = _scrollRect.vertical;
  106. if (_isHorizontal && _isVertical)
  107. {
  108. Debug.LogError("UI_InfiniteScroll doesn't support scrolling in both directions, please choose one direction (horizontal or vertical)");
  109. }
  110. SetItems();
  111. }
  112. else
  113. {
  114. Debug.LogError("UI_InfiniteScroll => No ScrollRect component found");
  115. }
  116. }
  117. void DisableGridComponents()
  118. {
  119. if (_isVertical)
  120. {
  121. _recordOffsetY = items[1].GetComponent<RectTransform>().anchoredPosition.y - items[0].GetComponent<RectTransform>().anchoredPosition.y;
  122. if (_recordOffsetY < 0)
  123. {
  124. _recordOffsetY *= -1;
  125. }
  126. _disableMarginY = _recordOffsetY * _itemCount / 2;
  127. }
  128. if (_isHorizontal)
  129. {
  130. _recordOffsetX = items[1].GetComponent<RectTransform>().anchoredPosition.x - items[0].GetComponent<RectTransform>().anchoredPosition.x;
  131. if (_recordOffsetX < 0)
  132. {
  133. _recordOffsetX *= -1;
  134. }
  135. _disableMarginX = _recordOffsetX * _itemCount / 2;
  136. }
  137. if (_verticalLayoutGroup)
  138. {
  139. _verticalLayoutGroup.enabled = false;
  140. }
  141. if (_horizontalLayoutGroup)
  142. {
  143. _horizontalLayoutGroup.enabled = false;
  144. }
  145. if (_contentSizeFitter)
  146. {
  147. _contentSizeFitter.enabled = false;
  148. }
  149. if (_gridLayoutGroup)
  150. {
  151. _gridLayoutGroup.enabled = false;
  152. }
  153. _hasDisabledGridComponents = true;
  154. }
  155. public void OnScroll(Vector2 pos)
  156. {
  157. if (!_hasDisabledGridComponents)
  158. DisableGridComponents();
  159. for (int i = 0; i < items.Count; i++)
  160. {
  161. if (_isHorizontal)
  162. {
  163. if (_scrollRect.transform.InverseTransformPoint(items[i].gameObject.transform.position).x > _disableMarginX + _threshold)
  164. {
  165. _newAnchoredPosition = items[i].anchoredPosition;
  166. _newAnchoredPosition.x -= _itemCount * _recordOffsetX;
  167. items[i].anchoredPosition = _newAnchoredPosition;
  168. _scrollRect.content.GetChild(_itemCount - 1).transform.SetAsFirstSibling();
  169. }
  170. else if (_scrollRect.transform.InverseTransformPoint(items[i].gameObject.transform.position).x < -_disableMarginX)
  171. {
  172. _newAnchoredPosition = items[i].anchoredPosition;
  173. _newAnchoredPosition.x += _itemCount * _recordOffsetX;
  174. items[i].anchoredPosition = _newAnchoredPosition;
  175. _scrollRect.content.GetChild(0).transform.SetAsLastSibling();
  176. }
  177. }
  178. if (_isVertical)
  179. {
  180. if (_scrollRect.transform.InverseTransformPoint(items[i].gameObject.transform.position).y > _disableMarginY + _threshold)
  181. {
  182. _newAnchoredPosition = items[i].anchoredPosition;
  183. _newAnchoredPosition.y -= _itemCount * _recordOffsetY;
  184. items[i].anchoredPosition = _newAnchoredPosition;
  185. _scrollRect.content.GetChild(_itemCount - 1).transform.SetAsFirstSibling();
  186. }
  187. else if (_scrollRect.transform.InverseTransformPoint(items[i].gameObject.transform.position).y < -_disableMarginY)
  188. {
  189. _newAnchoredPosition = items[i].anchoredPosition;
  190. _newAnchoredPosition.y += _itemCount * _recordOffsetY;
  191. items[i].anchoredPosition = _newAnchoredPosition;
  192. _scrollRect.content.GetChild(0).transform.SetAsLastSibling();
  193. }
  194. }
  195. }
  196. }
  197. }
  198. }