VirtualScrollRectPlus.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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> OnGetNextItem;
  15. public Func<int, VirtualScrollRectItem> OnGetPreviousItem;
  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 List<VirtualScrollRectItem> Children = new List<VirtualScrollRectItem>();
  24. public Dictionary<VirtualScrollRectItem, int> ChildrenDataIndexDictionary = new Dictionary<VirtualScrollRectItem, int>();
  25. #endregion
  26. public override void OnDrag(PointerEventData eventData)
  27. {
  28. base.OnDrag(eventData);
  29. if (!Inited)
  30. {
  31. return;
  32. }
  33. if (horizontal && !vertical)
  34. {
  35. if (horizontalNormalizedPosition <= 0)
  36. {
  37. Vector2 widthAndHeight = PreviousPage();
  38. Roll(new Vector2(-widthAndHeight.x, 0));
  39. OnHorizontalGreaterEqual1.SafeInvoke();
  40. }
  41. if (horizontalNormalizedPosition >= 1)
  42. {
  43. Vector2 widthAndHeight = NextPage();
  44. Roll(new Vector2(widthAndHeight.x, 0));
  45. OnHorizontalLessEqual0.SafeInvoke();
  46. }
  47. }
  48. else if (!horizontal && vertical)
  49. {
  50. if (verticalNormalizedPosition >= 1)
  51. {
  52. Vector2 widthAndHeight = PreviousPage();
  53. Roll(new Vector2(0, widthAndHeight.y));
  54. OnVerticalGreaterEqual1.SafeInvoke();
  55. }
  56. if (verticalNormalizedPosition <= 0)
  57. {
  58. Vector2 widthAndHeight = NextPage();
  59. Roll(new Vector2(0, -widthAndHeight.y));
  60. OnVerticalLessEqual0.SafeInvoke();
  61. }
  62. }
  63. }
  64. public void Init(int maxRollAmount, int maxChildAmount, Func<int, VirtualScrollRectItem> getNextItem, Func<int, VirtualScrollRectItem> getPreviousItem, Action<int, VirtualScrollRectItem> onSaveItem)
  65. {
  66. Inited = true;
  67. MaxRollAmount = maxRollAmount;
  68. MaxChildAmount = maxChildAmount;
  69. LayoutGroup = content.GetComponent<HorizontalOrVerticalLayoutGroup>();
  70. OnGetNextItem = getNextItem;
  71. OnGetPreviousItem = getPreviousItem;
  72. OnSaveItem = onSaveItem;
  73. }
  74. public void SaveAllChild()
  75. {
  76. while (Children.Count > 0)
  77. {
  78. SaveFirstChild();
  79. }
  80. }
  81. public void SaveChild(VirtualScrollRectItem item)
  82. {
  83. int dataIndex = ChildrenDataIndexDictionary[item];
  84. OnSaveItem.Invoke(dataIndex, item);
  85. Children.Remove(item);
  86. ChildrenDataIndexDictionary.Remove(item);
  87. if (Children.Count > 0)
  88. {
  89. FirstIndex = ChildrenDataIndexDictionary[Children[0]];
  90. LastIndex = ChildrenDataIndexDictionary[Children.Back(0)];
  91. }
  92. else
  93. {
  94. FirstIndex = 0;
  95. LastIndex = 0;
  96. }
  97. }
  98. public void SaveFirstChild()
  99. {
  100. SaveChild(Children[0]);
  101. }
  102. public void SaveLastChild()
  103. {
  104. SaveChild(Children.Back(0));
  105. }
  106. public VirtualScrollRectItem InsertChild(int siblingIndex, int dataIndex, VirtualScrollRectItem item, bool saveItem = false, int savaSiblingIndex = 0)
  107. {
  108. VirtualScrollRectItem savedItem = null;
  109. if (saveItem && Children.Count >= MaxChildAmount)
  110. {
  111. if (savaSiblingIndex == -1)
  112. {
  113. savedItem = Children.Back(0);
  114. }
  115. else
  116. {
  117. savedItem = Children[savaSiblingIndex];
  118. }
  119. if (siblingIndex == Children.Count)
  120. {
  121. siblingIndex--;
  122. }
  123. SaveChild(savedItem);
  124. }
  125. Children.Insert(siblingIndex, item);
  126. ChildrenDataIndexDictionary.Add(item, dataIndex);
  127. item.transform.SetSiblingIndex(siblingIndex);
  128. FirstIndex = ChildrenDataIndexDictionary[Children[0]];
  129. LastIndex = ChildrenDataIndexDictionary[Children.Back(0)];
  130. return savedItem;
  131. }
  132. public VirtualScrollRectItem InsertChildToFirst(int dataIndex, VirtualScrollRectItem item, bool saveItem = false, int savaSiblingIndex = 0)
  133. {
  134. return InsertChild(0, dataIndex, item, saveItem, savaSiblingIndex);
  135. }
  136. public VirtualScrollRectItem InsertChildToLast(int dataIndex, VirtualScrollRectItem item, bool saveItem = false, int savaSiblingIndex = 0)
  137. {
  138. return InsertChild(Children.Count, dataIndex, item, saveItem, savaSiblingIndex);
  139. }
  140. public Vector2 NextPage()
  141. {
  142. //Debug.LogWarning("NextPage");
  143. List<VirtualScrollRectItem> rolledItems = new List<VirtualScrollRectItem>();
  144. for (int i = 0; i < MaxRollAmount; i++)
  145. {
  146. int dataIndex = Children.Count == 0 ? 0 : LastIndex + 1;
  147. VirtualScrollRectItem item = OnGetNextItem.Invoke(dataIndex);
  148. if (item == null)
  149. {
  150. break;
  151. }
  152. else
  153. {
  154. VirtualScrollRectItem savedItem = InsertChildToLast(dataIndex, item, true, 0);
  155. if (savedItem != null)
  156. {
  157. rolledItems.Add(savedItem);
  158. }
  159. }
  160. }
  161. Vector2 widthAndHeight = new Vector2(rolledItems.MySum(item => item.RectTransform.rect.width), rolledItems.MySum(item => item.RectTransform.rect.height));
  162. widthAndHeight += new Vector2(LayoutGroup.spacing, LayoutGroup.spacing) * Mathf.Max(rolledItems.Count - 1, 0);
  163. return widthAndHeight;
  164. }
  165. public Vector2 PreviousPage()
  166. {
  167. //Debug.LogWarning("PreviousPage");
  168. List<VirtualScrollRectItem> rolledItems = new List<VirtualScrollRectItem>();
  169. for (int i = 0; i < MaxRollAmount; i++)
  170. {
  171. VirtualScrollRectItem item = OnGetPreviousItem.Invoke(FirstIndex-1);
  172. if (item == null)
  173. {
  174. break;
  175. }
  176. else
  177. {
  178. VirtualScrollRectItem savedItem = InsertChildToFirst(FirstIndex-1, item, true, -1);
  179. if (savedItem != null)
  180. {
  181. rolledItems.Add(savedItem);
  182. }
  183. }
  184. }
  185. Vector2 widthAndHeight = new Vector2(rolledItems.MySum(item => item.RectTransform.rect.width), rolledItems.MySum(item => item.RectTransform.rect.height));
  186. widthAndHeight += new Vector2(LayoutGroup.spacing, LayoutGroup.spacing)*Mathf.Max(rolledItems.Count - 1, 0);
  187. return widthAndHeight;
  188. }
  189. public void Roll(Vector2 contentOffset)
  190. {
  191. m_ContentStartPosition += contentOffset;
  192. }
  193. }