ScrollList.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  1. using System;
  2. using System.Collections.Generic;
  3. using Fort23.Core;
  4. using Fort23.Mono;
  5. using Fort23.UTool;
  6. using UnityEngine;
  7. using UnityEngine.UI;
  8. public class ScrollList : MonoBehaviour, IScrollListContent
  9. {
  10. public enum LayoutType
  11. {
  12. Left,
  13. Center,
  14. }
  15. // public Camera Camera;
  16. public ScrollRect ScrollRect;
  17. public Vector2 ScrollRectSizedata;
  18. public Vector2Int Page = new Vector2Int(1, 1);
  19. public float bottom;
  20. public RectTransform wdiget;
  21. public Vector2 sizeData = new Vector2();
  22. public List<IScorllListWidget> hindWidget = new List<IScorllListWidget>();
  23. public List<IScorllListWidget> showWidget = new List<IScorllListWidget>();
  24. protected int currIndex;
  25. // public Vector2 offSize;
  26. public bool isCustomizeHeight;
  27. public Vector2 posOff;
  28. public bool isDelay;
  29. public long delayTime;
  30. public bool isAdaptationWidth;
  31. private bool _isStartDelay;
  32. private bool hasAddedOffset = false;
  33. protected IScrollListContent m_scrollListContent;
  34. // private void Awake()
  35. // {
  36. // Init(this, 100);
  37. // }
  38. protected RectTransform myRectTransform;
  39. private float addY;
  40. protected int m_startIndex;
  41. private int _maxSize;
  42. private Vector3 onePos;
  43. private CTask isAwaitInitFinis;
  44. private bool _isBreak;
  45. private Vector2 _vel;
  46. public LayoutType layoutType = LayoutType.Left;
  47. public float overflowDistance;
  48. private void Awake()
  49. {
  50. if (myRectTransform == null)
  51. {
  52. myRectTransform = gameObject.GetComponent<RectTransform>();
  53. }
  54. onePos = myRectTransform.localPosition;
  55. }
  56. public void Break()
  57. {
  58. _isBreak = true;
  59. }
  60. public void Clear()
  61. {
  62. currIndex = 0;
  63. IScorllListWidget[] listWidgets = showWidget.ToArray();
  64. for (int i = 0; i < listWidgets.Length; i++)
  65. {
  66. HindIWidget(listWidgets[i]);
  67. }
  68. showWidget.Clear();
  69. ScrollRect.content.localPosition = onePos;
  70. ScrollRect.StopMovement();
  71. }
  72. /// <summary>
  73. /// 初始化
  74. /// </summary>
  75. /// <param name="scrollListContent"></param>
  76. /// <param name="maxSize"></param>
  77. /// <param name="startIndex"></param>
  78. public async CTask Init(IScrollListContent scrollListContent, int maxSize, int startIndex = 0)
  79. {
  80. if (startIndex < 0)
  81. {
  82. startIndex = 0;
  83. }
  84. if (ScrollRect == null)
  85. {
  86. ScrollRect = transform.GetComponentInParent<ScrollRect>(true);
  87. }
  88. RectTransform root = ScrollRect.GetComponent<RectTransform>();
  89. addY = 0;
  90. _isBreak = true;
  91. using (await CoroutineLockComponent.Instance.Wait(this.GetInstanceID().ToString()))
  92. {
  93. if (myRectTransform == null)
  94. {
  95. myRectTransform = gameObject.GetComponent<RectTransform>();
  96. }
  97. Clear();
  98. _maxSize = maxSize;
  99. if (isAdaptationWidth)
  100. {
  101. ScrollRect.SetLayoutHorizontal();
  102. await TimerComponent.Instance.WaitAsync(50);
  103. float fx = ((root.rect.size.x - posOff.x) / sizeData.x);
  104. int c = (int)fx;
  105. if (fx % 1 >= 0.9f)
  106. {
  107. c += 1;
  108. }
  109. Page.y = c;
  110. }
  111. if (layoutType == LayoutType.Center)
  112. {
  113. await TimerComponent.Instance.WaitAsync(30);
  114. float w = root.rect.width / 2;
  115. posOff = new Vector2(w, posOff.y);
  116. }
  117. await TimerComponent.Instance.WaitAsync(10);
  118. Vector2 lasetPos = myRectTransform.anchoredPosition;
  119. if (ScrollRect.horizontal)
  120. {
  121. myRectTransform.sizeDelta = new Vector2(sizeData.x * startIndex, myRectTransform.sizeDelta.y);
  122. myRectTransform.anchoredPosition =
  123. new Vector2(sizeData.x * startIndex * -1, myRectTransform.anchoredPosition.y);
  124. lasetPos = myRectTransform.anchoredPosition;
  125. m_startIndex = 0;
  126. currIndex = startIndex;
  127. }
  128. else if (ScrollRect.vertical)
  129. {
  130. // m_startIndex = startIndex;
  131. currIndex = startIndex;
  132. // Vector2 targetSizeDelta = CalculateTargetSizeDelta(startIndex);
  133. Vector2 targetSizeDelta = CalculateBottomSizeDelta(startIndex);
  134. targetSizeDelta += new Vector2(0, bottom);
  135. lasetPos = CalculateTargetPosition(startIndex);
  136. myRectTransform.sizeDelta = new Vector2(sizeData.x, targetSizeDelta.y);
  137. }
  138. _isBreak = false;
  139. m_scrollListContent = scrollListContent;
  140. CTaskAwaitBuffer cTaskAwaitBuffer = new CTaskAwaitBuffer();
  141. CTask<IScorllListWidget> ctask = Cread(currIndex, false);
  142. cTaskAwaitBuffer.AddTask(ctask);
  143. currIndex++;
  144. if (isDelay)
  145. {
  146. _isStartDelay = true;
  147. }
  148. await cTaskAwaitBuffer.WaitAll();
  149. ScrollRect.SetLayoutVertical();
  150. myRectTransform.anchoredPosition = lasetPos;
  151. ScrollRect.StopMovement();
  152. await onValueChanged(Vector2.zero, true);
  153. ScrollRect.onValueChanged.RemoveListener(onValueChanged2);
  154. ScrollRect.onValueChanged.AddListener(onValueChanged2);
  155. _isStartDelay = false;
  156. }
  157. }
  158. public void RemoveWidget(IScorllListWidget listWidget)
  159. {
  160. bool isHide = false;
  161. for (int i = 0; i < showWidget.Count; i++)
  162. {
  163. if (showWidget[i] == listWidget || isHide)
  164. {
  165. isHide = true;
  166. HindIWidget(showWidget[i]);
  167. i--;
  168. }
  169. }
  170. if (isHide)
  171. {
  172. if (showWidget.Count <= 0)
  173. {
  174. currIndex = 0;
  175. CTask<IScorllListWidget> ctask = Cread(currIndex, false);
  176. currIndex++;
  177. }
  178. onValueChanged(Vector2.zero, false);
  179. }
  180. }
  181. private void Update()
  182. {
  183. if (Input.GetKeyDown(KeyCode.Y))
  184. {
  185. HindWidget();
  186. }
  187. }
  188. protected async CTask<IScorllListWidget> Cread(int index, bool isUp)
  189. {
  190. int showIndex = index - m_startIndex;
  191. if (showWidget.Count > 100)
  192. {
  193. return null;
  194. }
  195. IScorllListWidget widget = await GetWidget(index);
  196. if (widget == null)
  197. {
  198. return null;
  199. }
  200. showWidget.Add(widget);
  201. int xoff = 0;
  202. int yoff = 0;
  203. if (ScrollRect.horizontal)
  204. {
  205. xoff = showIndex / Page.x;
  206. yoff = showIndex % Page.x;
  207. }
  208. else if (ScrollRect.vertical)
  209. {
  210. if (showIndex >= 0 || isCustomizeHeight)
  211. {
  212. yoff = showIndex / Page.y;
  213. xoff = showIndex % Page.y;
  214. }
  215. else
  216. {
  217. {
  218. xoff = showIndex % (Page.y + 1);
  219. yoff = showIndex / (Page.y + 1);
  220. }
  221. if (showIndex < 0)
  222. {
  223. xoff = Page.y - Math.Abs(xoff);
  224. yoff -= 1;
  225. }
  226. }
  227. }
  228. widget.Transform.gameObject.name = index.ToString();
  229. widget.Transform.SetParent(transform);
  230. widget.Transform.localScale = Vector3.one;
  231. if (!isCustomizeHeight)
  232. {
  233. widget.Transform.anchoredPosition =
  234. new Vector3(xoff * sizeData.x + posOff.x, -yoff * sizeData.y - addY - posOff.y);
  235. }
  236. else
  237. {
  238. float y = 0;
  239. if (isUp)
  240. {
  241. y = -5000000;
  242. }
  243. else
  244. {
  245. y = 5000000;
  246. }
  247. IScorllListWidget yWidget = null;
  248. for (int i = 0; i < showWidget.Count; i++)
  249. {
  250. IScorllListWidget scorllListWidget = showWidget[i];
  251. int c = scorllListWidget.index - m_startIndex;
  252. int lastY = c / Page.y;
  253. if (isUp)
  254. {
  255. if (lastY - yoff == 1)
  256. {
  257. float currY = scorllListWidget.Transform.localPosition.y;
  258. if (y < currY)
  259. {
  260. yWidget = scorllListWidget;
  261. y = currY;
  262. }
  263. }
  264. }
  265. else
  266. {
  267. if (yoff - lastY == 1)
  268. {
  269. float currY = scorllListWidget.Transform.localPosition.y;
  270. if (y > currY)
  271. {
  272. yWidget = scorllListWidget;
  273. y = currY;
  274. }
  275. }
  276. }
  277. }
  278. if (yWidget == null)
  279. {
  280. widget.Transform.localPosition = new Vector3(xoff * sizeData.x, -yoff * sizeData.y);
  281. }
  282. else
  283. {
  284. if (isUp)
  285. {
  286. Vector3 pos = new Vector3(0, y + widget.GetSize().y + sizeData.y);
  287. widget.Transform.localPosition = pos;
  288. }
  289. else
  290. {
  291. Vector3 pos = new Vector3(0, y - yWidget.GetSize().y - sizeData.y);
  292. widget.Transform.localPosition = pos;
  293. }
  294. }
  295. }
  296. if (ScrollRect.horizontal)
  297. {
  298. if (widget.Transform.localPosition.x > 0)
  299. {
  300. float x = widget.Transform.localPosition.x + sizeData.x;
  301. if (x < myRectTransform.sizeDelta.x)
  302. {
  303. x = myRectTransform.sizeDelta.x;
  304. }
  305. else
  306. {
  307. myRectTransform.sizeDelta = new Vector2(x + overflowDistance,
  308. myRectTransform.sizeDelta.y);
  309. }
  310. }
  311. // else
  312. // {
  313. // m_startIndex--;
  314. // float x = Math.Abs(widget.Transform.localPosition.x);
  315. // myRectTransform.sizeDelta += new Vector2(x,
  316. // 0);
  317. // MoveX(x);
  318. // }
  319. }
  320. else
  321. {
  322. float y = 0;
  323. if (isCustomizeHeight)
  324. {
  325. y = Math.Abs(widget.Transform.localPosition.y) + widget.GetSize().y;
  326. }
  327. else
  328. {
  329. y = Math.Abs(widget.Transform.localPosition.y) + sizeData.y;
  330. }
  331. if (widget.Transform.localPosition.y > 0)
  332. {
  333. if (isCustomizeHeight)
  334. {
  335. float addY = widget.GetSize().y + sizeData.y;
  336. myRectTransform.sizeDelta += new Vector2(0, addY);
  337. if (index >= _maxSize && !hasAddedOffset)
  338. {
  339. myRectTransform.sizeDelta += new Vector2(0, bottom);
  340. hasAddedOffset = true;
  341. }
  342. MoveY(addY);
  343. }
  344. else
  345. {
  346. myRectTransform.sizeDelta += new Vector2(0, sizeData.y);
  347. if (index >= _maxSize && !hasAddedOffset)
  348. {
  349. myRectTransform.sizeDelta += new Vector2(0, bottom);
  350. hasAddedOffset = true;
  351. }
  352. MoveY(sizeData.y);
  353. }
  354. }
  355. else
  356. {
  357. if (y > myRectTransform.sizeDelta.y)
  358. {
  359. myRectTransform.sizeDelta = new Vector2(myRectTransform.sizeDelta.x, y);
  360. }
  361. if (index >= _maxSize && !hasAddedOffset)
  362. {
  363. myRectTransform.sizeDelta += new Vector2(0, bottom);
  364. hasAddedOffset = true;
  365. }
  366. }
  367. }
  368. widget.Transform.anchorMax = Vector2.up;
  369. widget.Transform.anchorMin = Vector2.up;
  370. widget.Transform.pivot = Vector2.up;
  371. return widget;
  372. }
  373. protected void MoveY(float y)
  374. {
  375. ScrollRect.StopMovement();
  376. addY += y;
  377. ScrollRect.content.localPosition += new Vector3(0, y, 0);
  378. for (int i = 0; i < showWidget.Count; i++)
  379. {
  380. IScorllListWidget scorllListWidget = showWidget[i];
  381. Vector3 pos = scorllListWidget.Transform.localPosition;
  382. scorllListWidget.Transform.localPosition = new Vector3(pos.x, pos.y - y, pos.z);
  383. }
  384. }
  385. protected void MoveX(float x)
  386. {
  387. ScrollRect.StopMovement();
  388. // addY += y;
  389. myRectTransform.anchoredPosition -= new Vector2(x, 0);
  390. // ScrollRect.content.localPosition += new Vector3(x, 0, 0);
  391. for (int i = 0; i < showWidget.Count; i++)
  392. {
  393. IScorllListWidget scorllListWidget = showWidget[i];
  394. Vector3 pos = scorllListWidget.Transform.localPosition;
  395. scorllListWidget.Transform.localPosition = new Vector3(pos.x + x, pos.y, pos.z);
  396. }
  397. }
  398. protected void HindWidget()
  399. {
  400. if (showWidget.Count < 2)
  401. {
  402. return;
  403. }
  404. for (int i = 0; i < showWidget.Count; i++)
  405. {
  406. bool isShow = false;
  407. bool isHind = false;
  408. GetIsShow(showWidget[i], ref isShow, ref isHind);
  409. if (!isHind) //已经移除到了隐藏区域
  410. {
  411. HindIWidget(showWidget[i]);
  412. i--;
  413. if (showWidget.Count < 2)
  414. {
  415. return;
  416. }
  417. }
  418. }
  419. }
  420. public async void onValueChanged2(Vector2 pos)
  421. {
  422. onValueChanged(pos, false);
  423. }
  424. public async CTask onValueChanged(Vector2 pos, bool isInit)
  425. {
  426. if (_isBreak)
  427. {
  428. return;
  429. }
  430. if (!isInit && (_isBreak || _isStartDelay))
  431. {
  432. return;
  433. }
  434. // _vel = ScrollRect.velocity;
  435. using (await CoroutineLockComponent.Instance.Wait("123"))
  436. {
  437. if (_isBreak)
  438. {
  439. return;
  440. }
  441. hasAddedOffset = false;
  442. // ScrollRect.StopMovement();
  443. HindWidget();
  444. IScorllListWidget minWidget = null;
  445. IScorllListWidget maxWdiget = null;
  446. for (int i = 0; i < showWidget.Count; i++)
  447. {
  448. if (minWidget == null)
  449. {
  450. minWidget = showWidget[i];
  451. maxWdiget = showWidget[i];
  452. }
  453. else
  454. {
  455. if (minWidget.index > showWidget[i].index)
  456. {
  457. minWidget = showWidget[i];
  458. }
  459. if (maxWdiget.index < showWidget[i].index)
  460. {
  461. maxWdiget = showWidget[i];
  462. }
  463. }
  464. }
  465. if (minWidget == null || maxWdiget == null)
  466. {
  467. //检查是否需要生成第一个
  468. return;
  469. }
  470. bool isShow = false;
  471. bool isHind = false;
  472. GetIsShow(minWidget, ref isShow, ref isHind);
  473. bool isShow3 = false;
  474. bool isHind3 = false;
  475. GetIsShow(maxWdiget, ref isShow3, ref isHind3);
  476. if (isShow) //最小的在显示区域,需要生成下面的
  477. {
  478. IScorllListWidget wdiget = await Cread(minWidget.index - 1, true);
  479. if (wdiget != null)
  480. {
  481. bool isShow2 = true;
  482. bool isHind2 = false;
  483. while (isShow2 && wdiget != null)
  484. {
  485. if (_isBreak)
  486. {
  487. return;
  488. }
  489. GetIsShow(wdiget, ref isShow2, ref isHind2);
  490. if (isShow2)
  491. {
  492. if (_isStartDelay)
  493. {
  494. await TimerComponent.Instance.WaitAsync(delayTime);
  495. }
  496. if (_isBreak)
  497. {
  498. return;
  499. }
  500. wdiget = await Cread(wdiget.index - 1, true);
  501. }
  502. }
  503. }
  504. }
  505. if (isShow3) //最小的在显示区域,需要生成下面的
  506. {
  507. IScorllListWidget wdiget = await Cread(maxWdiget.index + 1, false);
  508. if (wdiget != null)
  509. {
  510. bool isShow2 = true;
  511. bool isHind2 = false;
  512. while (isShow2 && wdiget != null)
  513. {
  514. if (_isBreak)
  515. {
  516. return;
  517. }
  518. GetIsShow(wdiget, ref isShow2, ref isHind2);
  519. if (isShow2)
  520. {
  521. if (_isStartDelay)
  522. {
  523. await TimerComponent.Instance.WaitAsync(delayTime);
  524. }
  525. if (_isBreak)
  526. {
  527. return;
  528. }
  529. wdiget = await Cread(wdiget.index + 1, false);
  530. }
  531. }
  532. }
  533. }
  534. // ScrollRect.velocity = _vel;
  535. }
  536. // myRectTransform.sizeDelta=new Vector2(maxWdiget.index*)
  537. // Debug.Log(pos);
  538. }
  539. public void GetIsShow(IScorllListWidget widget, ref bool isShow, ref bool isHind)
  540. {
  541. RectTransform root = ScrollRect.GetComponent<RectTransform>();
  542. Vector2 posint = root.worldToLocalMatrix.MultiplyPoint3x4(widget.Transform.position);
  543. Vector2 size = widget.GetSize();
  544. isShow = false;
  545. isHind = false;
  546. Vector2 pos = Vector2.zero;
  547. float minx = pos.x - (root.rect.size.x * root.pivot.x);
  548. float miny = pos.y - (root.rect.size.y * root.pivot.y);
  549. float maxx = pos.x + (root.rect.size.x * (1 - root.pivot.x));
  550. float maxy = pos.y + (root.rect.size.y * (1 - root.pivot.y));
  551. Vector2 rootPos = posint;
  552. List<Vector2> widgetBox = GetBox(rootPos.x, rootPos.y - size.y, rootPos.x + size.x, rootPos.y);
  553. for (int i = 0; i < widgetBox.Count; i++)
  554. {
  555. Vector2 p = widgetBox[i];
  556. if (ScrollRect.vertical)
  557. {
  558. if (p.y > miny && p.y < maxy)
  559. {
  560. isShow = true;
  561. }
  562. if (p.y > miny - size.y - 100 &&
  563. p.y < maxy + size.y + 100)
  564. {
  565. isHind = true;
  566. }
  567. }
  568. else
  569. {
  570. if (p.x > minx && p.x < maxx)
  571. {
  572. isShow = true;
  573. }
  574. if (p.x > minx - size.x - 100 && p.x < maxx + size.x + 100)
  575. {
  576. isHind = true;
  577. }
  578. }
  579. }
  580. }
  581. protected List<Vector2> GetBox(float minx, float miny, float maxx, float maxy)
  582. {
  583. List<Vector2> s = new List<Vector2>();
  584. s.Add(new Vector2(minx, miny));
  585. s.Add(new Vector2(minx, maxy));
  586. s.Add(new Vector2(maxx, maxy));
  587. s.Add(new Vector2(maxx, miny));
  588. return s;
  589. }
  590. public async CTask<IScorllListWidget> GetWidget(int index)
  591. {
  592. IScorllListWidget listWidget =
  593. await m_scrollListContent.GetIScorllListWidget(index, transform.GetComponent<RectTransform>());
  594. if (listWidget == null)
  595. {
  596. return null;
  597. }
  598. listWidget.Transform.anchorMin = new Vector2(0, 1);
  599. listWidget.Transform.anchorMax = new Vector2(0, 1);
  600. listWidget.Transform.pivot = new Vector2(0, 1);
  601. listWidget.Transform.localScale = Vector3.one;
  602. listWidget.index = index;
  603. return listWidget;
  604. }
  605. public async CTask<IScorllListWidget> GetIScorllListWidget(int index, RectTransform root)
  606. {
  607. if (hindWidget.Count > 0)
  608. {
  609. IScorllListWidget listWidget = hindWidget[0];
  610. listWidget.Transform.gameObject.SetActive(true);
  611. hindWidget.RemoveAt(0);
  612. Debug.Log(index + "___" + listWidget.index);
  613. listWidget.index = index;
  614. return listWidget;
  615. }
  616. return null;
  617. }
  618. public void HindIWidget(IScorllListWidget widget)
  619. {
  620. showWidget.Remove(widget);
  621. m_scrollListContent.HindIScorllListWidget(widget);
  622. }
  623. public void HindIScorllListWidget(IScorllListWidget widget)
  624. {
  625. widget.Transform.gameObject.SetActive(false);
  626. Debug.Log("hindWidget___" + widget.index);
  627. hindWidget.Add(widget);
  628. }
  629. /// <summary>
  630. /// 计算目标索引对应的位置
  631. /// </summary>
  632. /// <param name="targetIndex">目标索引</param>
  633. /// <returns>目标位置</returns>
  634. private Vector2 CalculateTargetPosition(int targetIndex)
  635. {
  636. Vector2 targetPos = onePos; // 从初始位置开始计算
  637. if (ScrollRect.horizontal)
  638. {
  639. // 水平滚动:计算 X 轴位置
  640. int xOffset = (targetIndex - m_startIndex) / Page.x;
  641. targetPos.x -= xOffset * sizeData.x + posOff.x;
  642. }
  643. else if (ScrollRect.vertical)
  644. {
  645. // 垂直滚动:计算 Y 轴位置
  646. int yOffset = (targetIndex - m_startIndex) / Page.y;
  647. if (!isCustomizeHeight)
  648. {
  649. targetPos.y = yOffset * sizeData.y + posOff.y;
  650. }
  651. else
  652. {
  653. // 如果是自定义高度,假设高度固定,实际需根据 GetSize() 动态调整
  654. targetPos.y -= yOffset * sizeData.y + posOff.y;
  655. }
  656. }
  657. return targetPos;
  658. }
  659. /// <summary>
  660. /// 计算目标索引对应的 content sizeDelta
  661. /// </summary>
  662. /// <param name="targetIndex">目标索引</param>
  663. /// <returns>目标 sizeDelta</returns>
  664. private Vector2 CalculateTargetSizeDelta(int targetIndex)
  665. {
  666. Vector2 targetSizeDelta = myRectTransform.sizeDelta;
  667. if (ScrollRect.horizontal)
  668. {
  669. // 水平滚动:根据目标索引计算总宽度
  670. int totalColumns = (targetIndex + Page.y - 1) / Page.y; // 向上取整
  671. targetSizeDelta.x = totalColumns * sizeData.x + overflowDistance;
  672. targetSizeDelta.y = Page.y * sizeData.y; // 高度基于每列的控件数
  673. }
  674. else if (ScrollRect.vertical)
  675. {
  676. // 垂直滚动:根据目标索引计算总高度
  677. int totalRows = (targetIndex + Page.y - 1) / Page.y; // 向上取整
  678. if (!isCustomizeHeight)
  679. {
  680. targetSizeDelta.y = totalRows * sizeData.y + overflowDistance;
  681. targetSizeDelta.x = Page.y * sizeData.x; // 宽度基于每行的控件数
  682. }
  683. else
  684. {
  685. // 如果是自定义高度,简单假设高度固定,实际需根据已有控件动态计算
  686. targetSizeDelta.y = totalRows * sizeData.y + overflowDistance;
  687. targetSizeDelta.x = Page.y * sizeData.x;
  688. }
  689. }
  690. return targetSizeDelta;
  691. }
  692. private Vector2 CalculateBottomSizeDelta(int targetIndex)
  693. {
  694. Vector2 targetSizeDelta = myRectTransform.sizeDelta;
  695. RectTransform root = ScrollRect.GetComponent<RectTransform>();
  696. float viewportHeight;
  697. if (ScrollRectSizedata.y == 0)
  698. {
  699. viewportHeight = root.rect.height;
  700. }
  701. else
  702. {
  703. viewportHeight = ScrollRectSizedata.y;
  704. }
  705. // float viewportHeight = root.rect.height;
  706. if (ScrollRect.vertical)
  707. {
  708. // 计算可视行数
  709. float itemHeight = isCustomizeHeight ? sizeData.y : sizeData.y; // 简化,实际需动态获取
  710. int visibleRows = Mathf.CeilToInt(viewportHeight / itemHeight); // 向上取整
  711. // 计算最低端索引
  712. int bottomIndex = Mathf.Min(targetIndex + visibleRows * Page.y, _maxSize - 1);
  713. int totalRows = (bottomIndex + Page.y - 1) / Page.y; // 从 0 到 bottomIndex 的行数
  714. if (!isCustomizeHeight)
  715. {
  716. targetSizeDelta.y = totalRows * sizeData.y + overflowDistance;
  717. }
  718. else
  719. {
  720. // 动态高度简化处理
  721. targetSizeDelta.y = totalRows * sizeData.y + overflowDistance;
  722. // 实际应为:
  723. // float totalHeight = 0f;
  724. // for (int i = 0; i <= bottomIndex; i += Page.y)
  725. // totalHeight += (i < showWidget.Count) ? showWidget[i].GetSize().y : sizeData.y;
  726. // targetSizeDelta.y = totalHeight + overflowDistance;
  727. }
  728. targetSizeDelta.x = Page.y * sizeData.x;
  729. // Debug.Log(
  730. // $"最低端 sizeDelta - visibleRows: {visibleRows}, bottomIndex: {bottomIndex}, totalRows: {totalRows}, sizeDelta.y: {targetSizeDelta.y}");
  731. }
  732. else if (ScrollRect.horizontal)
  733. {
  734. int visibleColumns = Mathf.CeilToInt(root.rect.width / sizeData.x);
  735. int rightIndex = Mathf.Min(targetIndex + visibleColumns * Page.x, _maxSize - 1);
  736. int totalColumns = (rightIndex + Page.y - 1) / Page.y;
  737. targetSizeDelta.x = totalColumns * sizeData.x + overflowDistance;
  738. targetSizeDelta.y = Page.y * sizeData.y;
  739. }
  740. return targetSizeDelta;
  741. }
  742. }