ScrollList.cs 26 KB

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