ScrollList.cs 26 KB

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