ItemPosMgr.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. using UnityEngine.EventSystems;
  6. namespace SuperScrollView
  7. {
  8. public class ItemSizeGroup
  9. {
  10. public float[] mItemSizeArray = null;
  11. public float[] mItemStartPosArray = null;
  12. public int mItemCount = 0;
  13. int mDirtyBeginIndex = ItemPosMgr.mItemMaxCountPerGroup;
  14. public float mGroupSize = 0;
  15. public float mGroupStartPos = 0;
  16. public float mGroupEndPos = 0;
  17. public int mGroupIndex = 0;
  18. float mItemDefaultSize = 0;
  19. int mMaxNoZeroIndex = 0;
  20. public ItemSizeGroup(int index,float itemDefaultSize)
  21. {
  22. mGroupIndex = index;
  23. mItemDefaultSize = itemDefaultSize;
  24. Init();
  25. }
  26. public void Init()
  27. {
  28. mItemSizeArray = new float[ItemPosMgr.mItemMaxCountPerGroup];
  29. if (mItemDefaultSize != 0)
  30. {
  31. for (int i = 0; i < mItemSizeArray.Length; ++i)
  32. {
  33. mItemSizeArray[i] = mItemDefaultSize;
  34. }
  35. }
  36. mItemStartPosArray = new float[ItemPosMgr.mItemMaxCountPerGroup];
  37. mItemStartPosArray[0] = 0;
  38. mItemCount = ItemPosMgr.mItemMaxCountPerGroup;
  39. mGroupSize = mItemDefaultSize * mItemSizeArray.Length;
  40. if (mItemDefaultSize != 0)
  41. {
  42. mDirtyBeginIndex = 0;
  43. }
  44. else
  45. {
  46. mDirtyBeginIndex = ItemPosMgr.mItemMaxCountPerGroup;
  47. }
  48. }
  49. public float GetItemStartPos(int index)
  50. {
  51. return mGroupStartPos + mItemStartPosArray[index];
  52. }
  53. public bool IsDirty
  54. {
  55. get
  56. {
  57. return (mDirtyBeginIndex < mItemCount);
  58. }
  59. }
  60. public float SetItemSize(int index, float size)
  61. {
  62. if(index > mMaxNoZeroIndex && size > 0)
  63. {
  64. mMaxNoZeroIndex = index;
  65. }
  66. float old = mItemSizeArray[index];
  67. if (old == size)
  68. {
  69. return 0;
  70. }
  71. mItemSizeArray[index] = size;
  72. if (index < mDirtyBeginIndex)
  73. {
  74. mDirtyBeginIndex = index;
  75. }
  76. float ds = size - old;
  77. mGroupSize = mGroupSize + ds;
  78. return ds;
  79. }
  80. public void SetItemCount(int count)
  81. {
  82. if(count < mMaxNoZeroIndex)
  83. {
  84. mMaxNoZeroIndex = count;
  85. }
  86. if (mItemCount == count)
  87. {
  88. return;
  89. }
  90. mItemCount = count;
  91. RecalcGroupSize();
  92. }
  93. public void RecalcGroupSize()
  94. {
  95. mGroupSize = 0;
  96. for (int i = 0; i < mItemCount; ++i)
  97. {
  98. mGroupSize += mItemSizeArray[i];
  99. }
  100. }
  101. public int GetItemIndexByPos(float pos)
  102. {
  103. if (mItemCount == 0)
  104. {
  105. return -1;
  106. }
  107. int low = 0;
  108. int high = mItemCount - 1;
  109. if (mItemDefaultSize == 0f)
  110. {
  111. if(mMaxNoZeroIndex < 0)
  112. {
  113. mMaxNoZeroIndex = 0;
  114. }
  115. high = mMaxNoZeroIndex;
  116. }
  117. while (low <= high)
  118. {
  119. int mid = (low + high) / 2;
  120. float startPos = mItemStartPosArray[mid];
  121. float endPos = startPos + mItemSizeArray[mid];
  122. if (startPos <= pos && endPos >= pos)
  123. {
  124. return mid;
  125. }
  126. else if (pos > endPos)
  127. {
  128. low = mid + 1;
  129. }
  130. else
  131. {
  132. high = mid - 1;
  133. }
  134. }
  135. return -1;
  136. }
  137. public void UpdateAllItemStartPos()
  138. {
  139. if (mDirtyBeginIndex >= mItemCount)
  140. {
  141. return;
  142. }
  143. int startIndex = (mDirtyBeginIndex < 1) ? 1 : mDirtyBeginIndex;
  144. for (int i = startIndex; i < mItemCount; ++i)
  145. {
  146. mItemStartPosArray[i] = mItemStartPosArray[i - 1] + mItemSizeArray[i - 1];
  147. }
  148. mDirtyBeginIndex = mItemCount;
  149. }
  150. public void ClearOldData()
  151. {
  152. for (int i = mItemCount; i < ItemPosMgr.mItemMaxCountPerGroup; ++i)
  153. {
  154. mItemSizeArray[i] = 0;
  155. }
  156. }
  157. }
  158. public class ItemPosMgr
  159. {
  160. public const int mItemMaxCountPerGroup = 100;
  161. List<ItemSizeGroup> mItemSizeGroupList = new List<ItemSizeGroup>();
  162. int mDirtyBeginIndex = int.MaxValue;
  163. public float mTotalSize = 0;
  164. public float mItemDefaultSize = 20;
  165. int mMaxNotEmptyGroupIndex = 0;
  166. public ItemPosMgr(float itemDefaultSize)
  167. {
  168. mItemDefaultSize = itemDefaultSize;
  169. }
  170. public void SetItemMaxCount(int maxCount)
  171. {
  172. mDirtyBeginIndex = 0;
  173. mTotalSize = 0;
  174. int st = maxCount % mItemMaxCountPerGroup;
  175. int lastGroupItemCount = st;
  176. int needMaxGroupCount = maxCount / mItemMaxCountPerGroup;
  177. if (st > 0)
  178. {
  179. needMaxGroupCount++;
  180. }
  181. else
  182. {
  183. lastGroupItemCount = mItemMaxCountPerGroup;
  184. }
  185. int count = mItemSizeGroupList.Count;
  186. if (count > needMaxGroupCount)
  187. {
  188. int d = count - needMaxGroupCount;
  189. mItemSizeGroupList.RemoveRange(needMaxGroupCount, d);
  190. }
  191. else if (count < needMaxGroupCount)
  192. {
  193. if(count > 0)
  194. {
  195. mItemSizeGroupList[count - 1].ClearOldData();
  196. }
  197. int d = needMaxGroupCount - count;
  198. for (int i = 0; i < d; ++i)
  199. {
  200. ItemSizeGroup tGroup = new ItemSizeGroup(count + i, mItemDefaultSize);
  201. mItemSizeGroupList.Add(tGroup);
  202. }
  203. }
  204. else
  205. {
  206. if (count > 0)
  207. {
  208. mItemSizeGroupList[count - 1].ClearOldData();
  209. }
  210. }
  211. count = mItemSizeGroupList.Count;
  212. if((count-1) < mMaxNotEmptyGroupIndex)
  213. {
  214. mMaxNotEmptyGroupIndex = count - 1;
  215. }
  216. if(mMaxNotEmptyGroupIndex < 0)
  217. {
  218. mMaxNotEmptyGroupIndex = 0;
  219. }
  220. if (count == 0)
  221. {
  222. return;
  223. }
  224. for (int i = 0; i < count - 1; ++i)
  225. {
  226. mItemSizeGroupList[i].SetItemCount(mItemMaxCountPerGroup);
  227. }
  228. mItemSizeGroupList[count - 1].SetItemCount(lastGroupItemCount);
  229. for (int i = 0; i < count; ++i)
  230. {
  231. mTotalSize = mTotalSize + mItemSizeGroupList[i].mGroupSize;
  232. }
  233. }
  234. public void SetItemSize(int itemIndex, float size)
  235. {
  236. int groupIndex = itemIndex / mItemMaxCountPerGroup;
  237. int indexInGroup = itemIndex % mItemMaxCountPerGroup;
  238. ItemSizeGroup tGroup = mItemSizeGroupList[groupIndex];
  239. float changedSize = tGroup.SetItemSize(indexInGroup, size);
  240. if (changedSize != 0f)
  241. {
  242. if (groupIndex < mDirtyBeginIndex)
  243. {
  244. mDirtyBeginIndex = groupIndex;
  245. }
  246. }
  247. mTotalSize += changedSize;
  248. if(groupIndex > mMaxNotEmptyGroupIndex && size > 0)
  249. {
  250. mMaxNotEmptyGroupIndex = groupIndex;
  251. }
  252. }
  253. public float GetItemPos(int itemIndex)
  254. {
  255. Update(true);
  256. int groupIndex = itemIndex / mItemMaxCountPerGroup;
  257. int indexInGroup = itemIndex % mItemMaxCountPerGroup;
  258. return mItemSizeGroupList[groupIndex].GetItemStartPos(indexInGroup);
  259. }
  260. public bool GetItemIndexAndPosAtGivenPos(float pos, ref int index, ref float itemPos)
  261. {
  262. Update(true);
  263. index = 0;
  264. itemPos = 0f;
  265. int count = mItemSizeGroupList.Count;
  266. if (count == 0)
  267. {
  268. return true;
  269. }
  270. ItemSizeGroup hitGroup = null;
  271. int low = 0;
  272. int high = count - 1;
  273. if (mItemDefaultSize == 0f)
  274. {
  275. if(mMaxNotEmptyGroupIndex < 0)
  276. {
  277. mMaxNotEmptyGroupIndex = 0;
  278. }
  279. high = mMaxNotEmptyGroupIndex;
  280. }
  281. while (low <= high)
  282. {
  283. int mid = (low + high) / 2;
  284. ItemSizeGroup tGroup = mItemSizeGroupList[mid];
  285. if (tGroup.mGroupStartPos <= pos && tGroup.mGroupEndPos >= pos)
  286. {
  287. hitGroup = tGroup;
  288. break;
  289. }
  290. else if (pos > tGroup.mGroupEndPos)
  291. {
  292. low = mid + 1;
  293. }
  294. else
  295. {
  296. high = mid - 1;
  297. }
  298. }
  299. int hitIndex = -1;
  300. if (hitGroup != null)
  301. {
  302. hitIndex = hitGroup.GetItemIndexByPos(pos - hitGroup.mGroupStartPos);
  303. }
  304. else
  305. {
  306. return false;
  307. }
  308. if (hitIndex < 0)
  309. {
  310. return false;
  311. }
  312. index = hitIndex + hitGroup.mGroupIndex * mItemMaxCountPerGroup;
  313. itemPos = hitGroup.GetItemStartPos(hitIndex);
  314. return true;
  315. }
  316. public void Update(bool updateAll)
  317. {
  318. int count = mItemSizeGroupList.Count;
  319. if (count == 0)
  320. {
  321. return;
  322. }
  323. if (mDirtyBeginIndex >= count)
  324. {
  325. return;
  326. }
  327. int loopCount = 0;
  328. for (int i = mDirtyBeginIndex; i < count; ++i)
  329. {
  330. loopCount++;
  331. ItemSizeGroup tGroup = mItemSizeGroupList[i];
  332. mDirtyBeginIndex++;
  333. tGroup.UpdateAllItemStartPos();
  334. if (i == 0)
  335. {
  336. tGroup.mGroupStartPos = 0;
  337. tGroup.mGroupEndPos = tGroup.mGroupSize;
  338. }
  339. else
  340. {
  341. tGroup.mGroupStartPos = mItemSizeGroupList[i - 1].mGroupEndPos;
  342. tGroup.mGroupEndPos = tGroup.mGroupStartPos + tGroup.mGroupSize;
  343. }
  344. if (!updateAll && loopCount > 1)
  345. {
  346. return;
  347. }
  348. }
  349. }
  350. }
  351. }