VirtualScrollRectPlus.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using UnityEngine.EventSystems;
  6. using UnityEngine.UI;
  7. public class VirtualScrollRectPlus : ScrollRect
  8. {
  9. #region Config //上锁 解锁 对象池 需要外部实现
  10. public Action OnVerticalLessEqual0;
  11. public Action OnVerticalGreaterEqual1;
  12. public Action OnHorizontalLessEqual0;
  13. public Action OnHorizontalGreaterEqual1;
  14. public Func<int, VirtualScrollRectItem> GetNextItem;
  15. public Func<int, VirtualScrollRectItem> GetPreviousItem;
  16. public Action<int, VirtualScrollRectItem> OnSaveItem;
  17. public int FirstIndex;
  18. public int LastIndex;
  19. public bool Inited;
  20. public HorizontalOrVerticalLayoutGroup LayoutGroup;
  21. public int MaxRollAmount;
  22. public int MaxChildAmount;
  23. public bool NextPageLock;
  24. public bool PreviousPageLock;
  25. public List<VirtualScrollRectItem> Children = new List<VirtualScrollRectItem>();
  26. public Dictionary<VirtualScrollRectItem, int> ChildrenDataIndexDictionary = new Dictionary<VirtualScrollRectItem, int>();
  27. #endregion
  28. public override void OnDrag(PointerEventData eventData)
  29. {
  30. base.OnDrag(eventData);
  31. if (!Inited)
  32. {
  33. return;
  34. }
  35. if (horizontal && !vertical)
  36. {
  37. if (horizontalNormalizedPosition <= 0)
  38. {
  39. if (!PreviousPageLock)
  40. {
  41. Vector2 widthAndHeight = PreviousPage();
  42. Roll(new Vector2(-widthAndHeight.x, 0));
  43. }
  44. OnHorizontalGreaterEqual1.SafeInvoke();
  45. }
  46. if (horizontalNormalizedPosition >= 1)
  47. {
  48. if (!NextPageLock)
  49. {
  50. Vector2 widthAndHeight = NextPage();
  51. Roll(new Vector2(widthAndHeight.x, 0));
  52. }
  53. OnHorizontalLessEqual0.SafeInvoke();
  54. }
  55. }
  56. else if (!horizontal && vertical)
  57. {
  58. if (verticalNormalizedPosition >= 1)
  59. {
  60. if (!PreviousPageLock)
  61. {
  62. Vector2 widthAndHeight = PreviousPage();
  63. Roll(new Vector2(0, widthAndHeight.y));
  64. }
  65. OnVerticalGreaterEqual1.SafeInvoke();
  66. }
  67. if (verticalNormalizedPosition <= 0)
  68. {
  69. if (!NextPageLock)
  70. {
  71. Vector2 widthAndHeight = NextPage();
  72. Roll(new Vector2(0, -widthAndHeight.y));
  73. }
  74. OnVerticalLessEqual0.SafeInvoke();
  75. }
  76. }
  77. }
  78. public void Init(int maxRollAmount, int maxChildAmount, Func<int, VirtualScrollRectItem> getNextItem, Func<int, VirtualScrollRectItem> getPreviousItem, Action<int, VirtualScrollRectItem> onSaveItem)
  79. {
  80. Inited = true;
  81. MaxRollAmount = maxRollAmount;
  82. MaxChildAmount = maxChildAmount;
  83. LayoutGroup = content.GetComponent<HorizontalOrVerticalLayoutGroup>();
  84. GetNextItem = getNextItem;
  85. GetPreviousItem = getPreviousItem;
  86. OnSaveItem = onSaveItem;
  87. }
  88. public void SaveChild(VirtualScrollRectItem item)
  89. {
  90. int dataIndex = ChildrenDataIndexDictionary[item];
  91. OnSaveItem.Invoke(dataIndex, item);
  92. Children.Remove(item);
  93. ChildrenDataIndexDictionary.Remove(item);
  94. if (Children.Count > 0)
  95. {
  96. FirstIndex = ChildrenDataIndexDictionary[Children[0]];
  97. LastIndex = ChildrenDataIndexDictionary[Children.Back(0)];
  98. }
  99. else
  100. {
  101. FirstIndex = 0;
  102. LastIndex = 0;
  103. }
  104. }
  105. public void SaveFirstChild()
  106. {
  107. SaveChild(Children[0]);
  108. }
  109. public void SaveLastChild()
  110. {
  111. SaveChild(Children.Back(0));
  112. }
  113. public void InsertChild(int siblingIndex, int dataIndex, VirtualScrollRectItem item)
  114. {
  115. Children.Insert(siblingIndex, item);
  116. ChildrenDataIndexDictionary.Add(item, dataIndex);
  117. item.transform.SetSiblingIndex(siblingIndex);
  118. FirstIndex = ChildrenDataIndexDictionary[Children[0]];
  119. LastIndex = ChildrenDataIndexDictionary[Children.Back(0)];
  120. }
  121. public void InsertChildToFirst(int dataIndex, VirtualScrollRectItem item)
  122. {
  123. InsertChild(0, dataIndex, item);
  124. }
  125. public void InsertChildToLast(int dataIndex, VirtualScrollRectItem item)
  126. {
  127. InsertChild(Children.Count, dataIndex, item);
  128. }
  129. public Vector2 NextPage()
  130. {
  131. //Debug.LogWarning("NextPage");
  132. List<VirtualScrollRectItem> rolledItems = new List<VirtualScrollRectItem>();
  133. for (int i = 0; i < MaxRollAmount; i++)
  134. {
  135. int dataIndex = Children.Count == 0 ? 0 : LastIndex + 1;
  136. VirtualScrollRectItem item = GetNextItem.Invoke(dataIndex);
  137. if (item == null)
  138. {
  139. break;
  140. }
  141. else
  142. {
  143. if (Children.Count >= MaxChildAmount)
  144. {
  145. SaveFirstChild();
  146. rolledItems.Add(item);
  147. }
  148. InsertChildToLast(dataIndex, item);
  149. }
  150. }
  151. Vector2 widthAndHeight = new Vector2(rolledItems.MySum(item => item.RectTransform.rect.width), rolledItems.MySum(item => item.RectTransform.rect.height));
  152. widthAndHeight += new Vector2(LayoutGroup.spacing, LayoutGroup.spacing) * Mathf.Max(rolledItems.Count - 1, 0);
  153. return widthAndHeight;
  154. }
  155. public Vector2 PreviousPage()
  156. {
  157. //Debug.LogWarning("PreviousPage");
  158. List<VirtualScrollRectItem> rolledItems = new List<VirtualScrollRectItem>();
  159. for (int i = 0; i < MaxRollAmount; i++)
  160. {
  161. VirtualScrollRectItem item = GetPreviousItem.Invoke(FirstIndex-1);
  162. if (item == null)
  163. {
  164. break;
  165. }
  166. else
  167. {
  168. if (Children.Count >= MaxChildAmount)
  169. {
  170. SaveLastChild();
  171. rolledItems.Add(item);
  172. }
  173. InsertChildToFirst(FirstIndex-1, item);
  174. }
  175. }
  176. Vector2 widthAndHeight = new Vector2(rolledItems.MySum(item => item.RectTransform.rect.width), rolledItems.MySum(item => item.RectTransform.rect.height));
  177. widthAndHeight += new Vector2(LayoutGroup.spacing, LayoutGroup.spacing)*Mathf.Max(rolledItems.Count - 1, 0);
  178. return widthAndHeight;
  179. }
  180. public void Roll(Vector2 contentOffset)
  181. {
  182. m_ContentStartPosition += contentOffset;
  183. }
  184. }