LoopScrollRect.cs 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474
  1. using UnityEngine;
  2. using UnityEngine.Events;
  3. using UnityEngine.EventSystems;
  4. using System;
  5. using System.Collections.Generic;
  6. using LuaInterface;
  7. namespace UnityEngine.UI
  8. {
  9. //Lua中调用的回调函数
  10. public delegate void LuaUpdateCellCallback(LuaTable self, GameObject go, int dataIndex);
  11. [AddComponentMenu("")]
  12. [DisallowMultipleComponent]
  13. [RequireComponent(typeof(RectTransform))]
  14. public abstract class LoopScrollRect : UIBehaviour, IInitializePotentialDragHandler, IBeginDragHandler, IEndDragHandler, IDragHandler, IScrollHandler, ICanvasElement, ILayoutElement, ILayoutGroup
  15. {
  16. /// <summary>
  17. /// 更新Cell中的回调函数
  18. /// </summary>
  19. /// <param name="go"></param>
  20. /// <param name="dataIndex"></param>
  21. public delegate void UpdateCellCallback(GameObject go,int dataIndex);
  22. //==========LoopScrollRect==========
  23. [HideInInspector]
  24. public int totalCount; //negative means INFINITE mode
  25. [HideInInspector]
  26. [NonSerialized]
  27. public object[] objectsToFill = null;
  28. [HideInInspector]
  29. public bool reverseDirection = false;
  30. [HideInInspector]
  31. public float rubberScale = 1;
  32. [HideInInspector]
  33. public float threshold = 100;
  34. [HideInInspector]
  35. public bool lowGrid = false;
  36. private int m_nFrame = 3;
  37. private bool m_bClampedMove = false;
  38. protected int itemTypeStart = 0;
  39. protected int itemTypeEnd = 0;
  40. protected abstract float GetSize(RectTransform item);
  41. protected abstract float GetDimension(Vector2 vector);
  42. protected abstract Vector2 GetVector(float value);
  43. protected int directionSign = 0;
  44. private float m_ContentSpacing = -1;
  45. protected GridLayoutGroup m_GridLayout = null;
  46. protected float contentSpacing
  47. {
  48. get
  49. {
  50. if (m_ContentSpacing >= 0)
  51. {
  52. return m_ContentSpacing;
  53. }
  54. m_ContentSpacing = 0;
  55. if (content != null)
  56. {
  57. HorizontalOrVerticalLayoutGroup layout1 = content.GetComponent<HorizontalOrVerticalLayoutGroup>();
  58. if (layout1 != null)
  59. {
  60. m_ContentSpacing = layout1.spacing;
  61. }
  62. m_GridLayout = content.GetComponent<GridLayoutGroup>();
  63. if (m_GridLayout != null)
  64. {
  65. m_ContentSpacing = GetDimension(m_GridLayout.spacing);
  66. }
  67. }
  68. return m_ContentSpacing;
  69. }
  70. }
  71. protected int mContentCount = 0;
  72. public int ContentCount
  73. {
  74. get { return mContentCount; }
  75. set { mContentCount = value; }
  76. }
  77. private UpdateCellCallback mCellCallback = null;
  78. int mMovePos = 0;
  79. bool dirty = false;
  80. bool force = false;
  81. public UpdateCellCallback CellCallback
  82. {
  83. set { mCellCallback = value; }
  84. }
  85. private LuaUpdateCellCallback mLuaCellCallback = null;
  86. private LuaTable luaSelf = null;
  87. private LuaFunction mCellCallbackLua = null;
  88. public LuaFunction CellCallbackLua
  89. {
  90. set { mCellCallbackLua = value; }
  91. }
  92. private LuaFunction mLuaCellCallbackLua = null;
  93. private int m_ContentConstraintCount = 0;
  94. public int contentConstraintCount
  95. {
  96. get
  97. {
  98. if (m_ContentConstraintCount > 0)
  99. {
  100. return m_ContentConstraintCount;
  101. }
  102. m_ContentConstraintCount = 1;
  103. if (content != null)
  104. {
  105. GridLayoutGroup layout2 = content.GetComponent<GridLayoutGroup>();
  106. if (layout2 != null)
  107. {
  108. if (layout2.constraint == GridLayoutGroup.Constraint.Flexible)
  109. {
  110. DebugHelper.Log("[LoopScrollRect] Flexible not supported yet");
  111. }
  112. m_ContentConstraintCount = layout2.constraintCount;
  113. }
  114. }
  115. return m_ContentConstraintCount;
  116. }
  117. }
  118. public int ItemTypeStart
  119. {
  120. get { return itemTypeStart; }
  121. }
  122. public int ItemTypeEnd
  123. {
  124. get { return itemTypeEnd; }
  125. }
  126. protected virtual bool UpdateItems(Bounds viewBounds, Bounds contentBounds) { return false; }
  127. //==========LoopScrollRect==========
  128. public enum MovementType
  129. {
  130. Unrestricted, // Unrestricted movement -- can scroll forever
  131. Elastic, // Restricted but flexible -- can go past the edges, but springs back in place
  132. Clamped, // Restricted movement where it's not possible to go past the edges
  133. }
  134. public enum ScrollbarVisibility
  135. {
  136. Permanent,
  137. AutoHide,
  138. AutoHideAndExpandViewport,
  139. }
  140. [Serializable]
  141. public class ScrollRectEvent : UnityEvent<Vector2> { }
  142. [SerializeField]
  143. private Transform m_Cell;
  144. public Transform Cell { get { return m_Cell; } set { m_Cell = value; } }
  145. [SerializeField]
  146. private RectTransform m_Content;
  147. public RectTransform content { get { return m_Content; } set { m_Content = value; } }
  148. [SerializeField]
  149. private bool m_Horizontal = true;
  150. public bool horizontal { get { return m_Horizontal; } set { m_Horizontal = value; } }
  151. [SerializeField]
  152. private bool m_Vertical = true;
  153. public bool vertical { get { return m_Vertical; } set { m_Vertical = value; } }
  154. [SerializeField]
  155. private MovementType m_MovementType = MovementType.Elastic;
  156. public MovementType movementType { get { return m_MovementType; } set { m_MovementType = value; } }
  157. [SerializeField]
  158. private float m_Elasticity = 0.1f; // Only used for MovementType.Elastic
  159. public float elasticity { get { return m_Elasticity; } set { m_Elasticity = value; } }
  160. [SerializeField]
  161. private bool m_Inertia = true;
  162. public bool inertia { get { return m_Inertia; } set { m_Inertia = value; } }
  163. [SerializeField]
  164. private float m_DecelerationRate = 0.135f; // Only used when inertia is enabled
  165. public float decelerationRate { get { return m_DecelerationRate; } set { m_DecelerationRate = value; } }
  166. [SerializeField]
  167. private float m_ScrollSensitivity = 1.0f;
  168. public float scrollSensitivity { get { return m_ScrollSensitivity; } set { m_ScrollSensitivity = value; } }
  169. [SerializeField]
  170. private RectTransform m_Viewport;
  171. public RectTransform viewport { get { return m_Viewport; } set { m_Viewport = value; SetDirtyCaching(); } }
  172. [SerializeField]
  173. private Scrollbar m_HorizontalScrollbar;
  174. public Scrollbar horizontalScrollbar
  175. {
  176. get
  177. {
  178. return m_HorizontalScrollbar;
  179. }
  180. set
  181. {
  182. if (m_HorizontalScrollbar)
  183. m_HorizontalScrollbar.onValueChanged.RemoveListener(SetHorizontalNormalizedPosition);
  184. m_HorizontalScrollbar = value;
  185. if (m_HorizontalScrollbar)
  186. m_HorizontalScrollbar.onValueChanged.AddListener(SetHorizontalNormalizedPosition);
  187. SetDirtyCaching();
  188. }
  189. }
  190. [SerializeField]
  191. private Scrollbar m_VerticalScrollbar;
  192. public Scrollbar verticalScrollbar
  193. {
  194. get
  195. {
  196. return m_VerticalScrollbar;
  197. }
  198. set
  199. {
  200. if (m_VerticalScrollbar)
  201. m_VerticalScrollbar.onValueChanged.RemoveListener(SetVerticalNormalizedPosition);
  202. m_VerticalScrollbar = value;
  203. if (m_VerticalScrollbar)
  204. m_VerticalScrollbar.onValueChanged.AddListener(SetVerticalNormalizedPosition);
  205. SetDirtyCaching();
  206. }
  207. }
  208. [SerializeField]
  209. private ScrollbarVisibility m_HorizontalScrollbarVisibility;
  210. public ScrollbarVisibility horizontalScrollbarVisibility { get { return m_HorizontalScrollbarVisibility; } set { m_HorizontalScrollbarVisibility = value; SetDirtyCaching(); } }
  211. [SerializeField]
  212. private ScrollbarVisibility m_VerticalScrollbarVisibility;
  213. public ScrollbarVisibility verticalScrollbarVisibility { get { return m_VerticalScrollbarVisibility; } set { m_VerticalScrollbarVisibility = value; SetDirtyCaching(); } }
  214. [SerializeField]
  215. private float m_HorizontalScrollbarSpacing;
  216. public float horizontalScrollbarSpacing { get { return m_HorizontalScrollbarSpacing; } set { m_HorizontalScrollbarSpacing = value; SetDirty(); } }
  217. [SerializeField]
  218. private float m_VerticalScrollbarSpacing;
  219. public float verticalScrollbarSpacing { get { return m_VerticalScrollbarSpacing; } set { m_VerticalScrollbarSpacing = value; SetDirty(); } }
  220. [SerializeField]
  221. private ScrollRectEvent m_OnValueChanged = new ScrollRectEvent();
  222. public ScrollRectEvent onValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
  223. // The offset from handle position to mouse down position
  224. private Vector2 m_PointerStartLocalCursor = Vector2.zero;
  225. private Vector2 m_ContentStartPosition = Vector2.zero;
  226. private RectTransform m_ViewRect;
  227. protected RectTransform viewRect
  228. {
  229. get
  230. {
  231. if (m_ViewRect == null)
  232. m_ViewRect = m_Viewport;
  233. if (m_ViewRect == null)
  234. m_ViewRect = (RectTransform)transform;
  235. return m_ViewRect;
  236. }
  237. }
  238. private Bounds m_ContentBounds;
  239. private Bounds m_ViewBounds;
  240. private Vector2 m_Velocity;
  241. public Vector2 velocity { get { return m_Velocity; } set { m_Velocity = value; } }
  242. private bool m_Dragging;
  243. public bool IsDragging { get { return m_Dragging; } }
  244. private Vector2 m_PrevPosition = Vector2.zero;
  245. private Bounds m_PrevContentBounds;
  246. private Bounds m_PrevViewBounds;
  247. [NonSerialized]
  248. private bool m_HasRebuiltLayout = false;
  249. private bool m_HSliderExpand;
  250. private bool m_VSliderExpand;
  251. private float m_HSliderHeight;
  252. private float m_VSliderWidth;
  253. [System.NonSerialized]
  254. private RectTransform m_Rect;
  255. private RectTransform rectTransform
  256. {
  257. get
  258. {
  259. if (m_Rect == null)
  260. m_Rect = GetComponent<RectTransform>();
  261. return m_Rect;
  262. }
  263. }
  264. private RectTransform m_HorizontalScrollbarRect;
  265. private RectTransform m_VerticalScrollbarRect;
  266. private DrivenRectTransformTracker m_Tracker;
  267. public System.Action mOnBeginDragAction = null;
  268. public System.Action mOnDragingAction = null;
  269. public System.Action mOnEndDragAction = null;
  270. private LuaFunction mOnBeginDragLuaFun = null;
  271. private LuaFunction mOnDragLuaFun = null;
  272. private LuaFunction mOnEndDragLuaFun = null;
  273. protected LoopScrollRect()
  274. {
  275. flexibleWidth = -1;
  276. }
  277. public void ForbidMove()
  278. {
  279. m_MovementType = MovementType.Clamped;
  280. }
  281. int preIdx = 0;
  282. //==========LoopScrollRect==========
  283. void UpdateScrollCell(Transform go,int idx)
  284. {
  285. if(mCellCallback != null)
  286. {
  287. mCellCallback(go.gameObject, idx);
  288. }
  289. if(luaSelf!=null && mLuaCellCallback!=null)
  290. {
  291. preIdx = idx;
  292. mLuaCellCallback.DynamicInvoke(luaSelf, go.gameObject,idx);
  293. }
  294. }
  295. public void ClearCells()
  296. {
  297. if (Application.isPlaying)
  298. {
  299. /*Vector2 sizeDelta = m_Content.sizeDelta;
  300. sizeDelta.x = 0;
  301. sizeDelta.y = 0;
  302. m_Content.sizeDelta = sizeDelta;*/
  303. itemTypeStart = 0;
  304. itemTypeEnd = 0;
  305. totalCount = 0;
  306. objectsToFill = null;
  307. for (int i = content.childCount - 1; i >= 0; i--)
  308. {
  309. GarbageGo(content.GetChild(i).gameObject);
  310. }
  311. //m_Content.anchoredPosition3D = Vector3.zero;
  312. }
  313. }
  314. public void ClearAnchoredPostion()
  315. {
  316. if (null == m_Content)
  317. return;
  318. m_Content.anchoredPosition3D = Vector3.zero;
  319. }
  320. public void ResetClampOffset()
  321. {
  322. m_nFrame = 3;
  323. m_bClampedMove = true;
  324. }
  325. public void Reset()
  326. {
  327. itemTypeStart = 0;
  328. itemTypeEnd = 0;
  329. totalCount = 0;
  330. objectsToFill = null;
  331. }
  332. public void DestroyCells()
  333. {
  334. DestroyCells(false);
  335. }
  336. public void DestroyCells(bool immediate)
  337. {
  338. itemTypeStart = 0;
  339. itemTypeEnd = 0;
  340. totalCount = 0;
  341. for (int i = content.childCount-1; i>=0;i--)
  342. {
  343. //这里改成DestroyImmediate确保childCount立即更新
  344. if(immediate)
  345. {
  346. content.GetChild(i).gameObject.DestroyImmediate();
  347. }
  348. else
  349. {
  350. GameObject.Destroy(content.GetChild(i).gameObject);
  351. }
  352. //
  353. }
  354. while(mAvailableObj.Count > 0)
  355. {
  356. if(immediate)
  357. {
  358. var go = mAvailableObj.Pop();
  359. if (go != null)
  360. go.DestroyImmediate();
  361. }
  362. else
  363. {
  364. GameObject.Destroy(mAvailableObj.Pop());
  365. }
  366. }
  367. }
  368. public void ResetItemTypeStart()
  369. {
  370. itemTypeStart = 0;
  371. }
  372. public void RefreshCells()
  373. {
  374. if (Application.isPlaying && this.isActiveAndEnabled)
  375. {
  376. itemTypeEnd = itemTypeStart;
  377. // recycle items if we can
  378. for (int i = 0; i < content.childCount; i++)
  379. {
  380. if (itemTypeEnd < totalCount)
  381. {
  382. UpdateScrollCell(content.GetChild(i), itemTypeEnd);
  383. itemTypeEnd++;
  384. }
  385. else
  386. {
  387. GarbageGo(content.GetChild(i).gameObject);
  388. i--;
  389. }
  390. }
  391. }
  392. }
  393. public void RefreshCellsData()
  394. {
  395. if (Application.isPlaying && this.isActiveAndEnabled)
  396. {
  397. for (int idx = itemTypeStart; idx < totalCount; idx++)
  398. {
  399. int childIdx = idx - itemTypeStart;
  400. if (childIdx < content.childCount)
  401. {
  402. UpdateScrollCell(content.GetChild(childIdx), idx);
  403. }
  404. }
  405. }
  406. }
  407. public void MoveTo(int index)
  408. {
  409. if (index < 0 || index >= totalCount)
  410. return;
  411. mMovePos = index;
  412. dirty = true;
  413. force = false;
  414. }
  415. public void ForceMoveTo(int index)
  416. {
  417. if (index < 0 || index >= totalCount)
  418. return;
  419. mMovePos = index;
  420. dirty = true;
  421. force = true;
  422. }
  423. public void SetItemStartIdx(int index)
  424. {
  425. itemTypeStart = index;
  426. itemTypeEnd = index;
  427. }
  428. public void SetUpdateCellCallback(LuaTable self,LuaUpdateCellCallback cb)
  429. {
  430. luaSelf = self;
  431. mLuaCellCallback = cb;
  432. }
  433. public void SetDragLuaCallback(LuaFunction cb)
  434. {
  435. mOnDragLuaFun = cb;
  436. }
  437. public void SetOnDragLuaCallback(LuaFunction cb)
  438. {
  439. mOnBeginDragLuaFun = cb;
  440. }
  441. public void SetOnEndDragLuaCallback(LuaFunction cb)
  442. {
  443. mOnEndDragLuaFun = cb;
  444. }
  445. protected float NewItemAtStart()
  446. {
  447. if (totalCount >= 0 && itemTypeStart - contentConstraintCount < 0)
  448. {
  449. return 0;
  450. }
  451. float size = 0;
  452. for (int i = 0; i < contentConstraintCount; i++)
  453. {
  454. itemTypeStart--;
  455. RectTransform newItem = InstantiateNextItem(itemTypeStart);
  456. newItem.SetAsFirstSibling();
  457. size = Mathf.Max(GetSize(newItem), size);
  458. }
  459. if (!reverseDirection)
  460. {
  461. Vector2 offset = GetVector(size);
  462. content.anchoredPosition += offset;
  463. m_PrevPosition += offset;
  464. m_ContentStartPosition += offset;
  465. }
  466. return size;
  467. }
  468. protected float DeleteItemAtStart()
  469. {
  470. if ((totalCount >= 0 && itemTypeEnd >= totalCount - 1) || content.childCount == 0)
  471. {
  472. return 0;
  473. }
  474. float size = 0;
  475. for (int i = 0; i < contentConstraintCount; i++)
  476. {
  477. RectTransform oldItem = content.GetChild(0) as RectTransform;
  478. size = Mathf.Max(GetSize(oldItem), size);
  479. GarbageGo(oldItem.gameObject);
  480. itemTypeStart++;
  481. if (content.childCount == 0)
  482. {
  483. break;
  484. }
  485. }
  486. if (!reverseDirection)
  487. {
  488. Vector2 offset = GetVector(size);
  489. content.anchoredPosition -= offset;
  490. m_PrevPosition -= offset;
  491. m_ContentStartPosition -= offset;
  492. }
  493. return size;
  494. }
  495. /// <summary>
  496. /// 在尾部追加一个元素
  497. /// </summary>
  498. /// <returns></returns>
  499. protected float NewItemAtEnd()
  500. {
  501. if (totalCount >= 0 && itemTypeEnd >= totalCount)
  502. {
  503. return 0;
  504. }
  505. float size = 0;
  506. // issue 4: fill lines to end first
  507. int count = contentConstraintCount - (content.childCount % contentConstraintCount);
  508. for (int i = 0; i < count; i++)
  509. {
  510. RectTransform newItem = InstantiateNextItem(itemTypeEnd);
  511. size = Mathf.Max(GetSize(newItem), size);
  512. itemTypeEnd++;
  513. if (totalCount >= 0 && itemTypeEnd >= totalCount)
  514. {
  515. break;
  516. }
  517. }
  518. if (reverseDirection)
  519. {
  520. Vector2 offset = GetVector(size);
  521. content.anchoredPosition -= offset;
  522. m_PrevPosition -= offset;
  523. m_ContentStartPosition -= offset;
  524. }
  525. return size;
  526. }
  527. /// <summary>
  528. /// 删除列表后面的元素
  529. /// </summary>
  530. /// <returns></returns>
  531. protected float DeleteItemAtEnd()
  532. {
  533. if ((totalCount >= 0 && itemTypeStart < contentConstraintCount) || content.childCount == 0 || itemTypeEnd == 0)
  534. {
  535. return 0;
  536. }
  537. float size = 0;
  538. for (int i = 0; i < contentConstraintCount; i++)
  539. {
  540. RectTransform oldItem = content.GetChild(content.childCount - 1) as RectTransform;
  541. size = Mathf.Max(GetSize(oldItem), size);
  542. GarbageGo(oldItem.gameObject);
  543. itemTypeEnd--;
  544. if (itemTypeEnd % contentConstraintCount == 0 || content.childCount == 0)
  545. {
  546. break; //just delete the whole row
  547. }
  548. }
  549. if (reverseDirection)
  550. {
  551. Vector2 offset = GetVector(size);
  552. content.anchoredPosition += offset;
  553. m_PrevPosition += offset;
  554. m_ContentStartPosition += offset;
  555. }
  556. return size;
  557. }
  558. private RectTransform InstantiateNextItem(int itemIdx)
  559. {
  560. GameObject go = CreateGO();
  561. if (go == null) return null;
  562. RectTransform nextItem = go.GetComponent<RectTransform>();
  563. nextItem.transform.SetParent(content, false);
  564. nextItem.gameObject.SetActive(true);
  565. UpdateScrollCell(nextItem, itemIdx);
  566. return nextItem;
  567. }
  568. Stack<GameObject> mAvailableObj = new Stack<GameObject>();
  569. GameObject CreateGO()
  570. {
  571. if (m_Cell == null) return null;
  572. GameObject go = null;
  573. if(mAvailableObj.Count > 0)
  574. {
  575. go = mAvailableObj.Pop();
  576. }else
  577. {
  578. go = GameObject.Instantiate(m_Cell.gameObject);
  579. go.transform.SetParent(content, false);
  580. go.transform.localScale = m_Cell.transform.localScale;
  581. }
  582. return go;
  583. }
  584. void GarbageGo(GameObject go)
  585. {
  586. go.SetActive(false);
  587. go.transform.SetParent(this.transform, false);
  588. mAvailableObj.Push(go);
  589. }
  590. //==========LoopScrollRect==========
  591. public virtual void Rebuild(CanvasUpdate executing)
  592. {
  593. if (executing == CanvasUpdate.Prelayout)
  594. {
  595. UpdateCachedData();
  596. }
  597. if (executing == CanvasUpdate.PostLayout)
  598. {
  599. UpdateBounds(false);
  600. UpdateScrollbars(Vector2.zero);
  601. UpdatePrevData();
  602. m_HasRebuiltLayout = true;
  603. }
  604. }
  605. public virtual void LayoutComplete()
  606. { }
  607. public virtual void GraphicUpdateComplete()
  608. { }
  609. void UpdateCachedData()
  610. {
  611. Transform transform = this.transform;
  612. m_HorizontalScrollbarRect = m_HorizontalScrollbar == null ? null : m_HorizontalScrollbar.transform as RectTransform;
  613. m_VerticalScrollbarRect = m_VerticalScrollbar == null ? null : m_VerticalScrollbar.transform as RectTransform;
  614. // These are true if either the elements are children, or they don't exist at all.
  615. bool viewIsChild = (viewRect.parent == transform);
  616. bool hScrollbarIsChild = (!m_HorizontalScrollbarRect || m_HorizontalScrollbarRect.parent == transform);
  617. bool vScrollbarIsChild = (!m_VerticalScrollbarRect || m_VerticalScrollbarRect.parent == transform);
  618. bool allAreChildren = (viewIsChild && hScrollbarIsChild && vScrollbarIsChild);
  619. m_HSliderExpand = allAreChildren && m_HorizontalScrollbarRect && horizontalScrollbarVisibility == ScrollbarVisibility.AutoHideAndExpandViewport;
  620. m_VSliderExpand = allAreChildren && m_VerticalScrollbarRect && verticalScrollbarVisibility == ScrollbarVisibility.AutoHideAndExpandViewport;
  621. m_HSliderHeight = (m_HorizontalScrollbarRect == null ? 0 : m_HorizontalScrollbarRect.rect.height);
  622. m_VSliderWidth = (m_VerticalScrollbarRect == null ? 0 : m_VerticalScrollbarRect.rect.width);
  623. }
  624. protected override void OnEnable()
  625. {
  626. base.OnEnable();
  627. if (m_HorizontalScrollbar)
  628. m_HorizontalScrollbar.onValueChanged.AddListener(SetHorizontalNormalizedPosition);
  629. if (m_VerticalScrollbar)
  630. m_VerticalScrollbar.onValueChanged.AddListener(SetVerticalNormalizedPosition);
  631. CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
  632. }
  633. protected override void OnDisable()
  634. {
  635. CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild(this);
  636. if (m_HorizontalScrollbar)
  637. m_HorizontalScrollbar.onValueChanged.RemoveListener(SetHorizontalNormalizedPosition);
  638. if (m_VerticalScrollbar)
  639. m_VerticalScrollbar.onValueChanged.RemoveListener(SetVerticalNormalizedPosition);
  640. m_HasRebuiltLayout = false;
  641. m_Tracker.Clear();
  642. m_Velocity = Vector2.zero;
  643. LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
  644. base.OnDisable();
  645. }
  646. public override bool IsActive()
  647. {
  648. return base.IsActive() && m_Content != null;
  649. }
  650. private void EnsureLayoutHasRebuilt()
  651. {
  652. if (!m_HasRebuiltLayout && !CanvasUpdateRegistry.IsRebuildingLayout())
  653. Canvas.ForceUpdateCanvases();
  654. }
  655. public virtual void StopMovement()
  656. {
  657. m_Velocity = Vector2.zero;
  658. }
  659. public void SetScrollToPosition(Vector2 pos)
  660. {
  661. DebugHelper.LogError(pos);
  662. SetContentAnchoredPosition(pos);
  663. }
  664. public virtual void OnScroll(PointerEventData data)
  665. {
  666. if (!IsActive())
  667. return;
  668. EnsureLayoutHasRebuilt();
  669. UpdateBounds();
  670. Vector2 delta = data.scrollDelta;
  671. // Down is positive for scroll events, while in UI system up is positive.
  672. delta.y *= -1;
  673. if (vertical && !horizontal)
  674. {
  675. if (Mathf.Abs(delta.x) > Mathf.Abs(delta.y))
  676. delta.y = delta.x;
  677. delta.x = 0;
  678. }
  679. if (horizontal && !vertical)
  680. {
  681. if (Mathf.Abs(delta.y) > Mathf.Abs(delta.x))
  682. delta.x = delta.y;
  683. delta.y = 0;
  684. }
  685. Vector2 position = m_Content.anchoredPosition;
  686. position += delta * m_ScrollSensitivity;
  687. if (m_MovementType == MovementType.Clamped)
  688. position += CalculateOffset(position - m_Content.anchoredPosition);
  689. SetContentAnchoredPosition(position);
  690. UpdateBounds();
  691. }
  692. public virtual void OnInitializePotentialDrag(PointerEventData eventData)
  693. {
  694. if (eventData.button != PointerEventData.InputButton.Left)
  695. return;
  696. m_Velocity = Vector2.zero;
  697. }
  698. public virtual void OnBeginDrag(PointerEventData eventData)
  699. {
  700. if (eventData.button != PointerEventData.InputButton.Left)
  701. return;
  702. if (!IsActive())
  703. return;
  704. UpdateBounds();
  705. m_PointerStartLocalCursor = Vector2.zero;
  706. RectTransformUtility.ScreenPointToLocalPointInRectangle(viewRect, eventData.position, eventData.pressEventCamera, out m_PointerStartLocalCursor);
  707. m_ContentStartPosition = m_Content.anchoredPosition;
  708. m_Dragging = true;
  709. if (mOnBeginDragAction != null)
  710. mOnBeginDragAction();
  711. if(mOnBeginDragLuaFun != null && luaSelf != null)
  712. mOnBeginDragLuaFun.Call(luaSelf);
  713. }
  714. public virtual void OnEndDrag(PointerEventData eventData)
  715. {
  716. if (eventData.button != PointerEventData.InputButton.Left)
  717. return;
  718. m_Dragging = false;
  719. if (mOnEndDragAction != null)
  720. mOnEndDragAction();
  721. if (mOnEndDragLuaFun != null && luaSelf != null)
  722. mOnEndDragLuaFun.Call(luaSelf);
  723. }
  724. public virtual void OnDrag(PointerEventData eventData)
  725. {
  726. if (eventData.button != PointerEventData.InputButton.Left)
  727. return;
  728. if (!IsActive())
  729. return;
  730. Vector2 localCursor;
  731. if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(viewRect, eventData.position, eventData.pressEventCamera, out localCursor))
  732. return;
  733. UpdateBounds();
  734. var pointerDelta = localCursor - m_PointerStartLocalCursor;
  735. Vector2 position = m_ContentStartPosition + pointerDelta;
  736. // Offset to get content into place in the view.
  737. Vector2 offset = CalculateOffset(position - m_Content.anchoredPosition);
  738. position += offset;
  739. if (m_MovementType == MovementType.Elastic)
  740. {
  741. //==========LoopScrollRect==========
  742. if (offset.x != 0)
  743. position.x = position.x - RubberDelta(offset.x, m_ViewBounds.size.x) * rubberScale;
  744. if (offset.y != 0)
  745. position.y = position.y - RubberDelta(offset.y, m_ViewBounds.size.y) * rubberScale;
  746. //==========LoopScrollRect==========
  747. }
  748. SetContentAnchoredPosition(position);
  749. if (mOnDragingAction != null)
  750. mOnDragingAction();
  751. if (mOnDragLuaFun != null && luaSelf != null)
  752. mOnDragLuaFun.Call(luaSelf);
  753. }
  754. protected virtual void SetContentAnchoredPosition(Vector2 position)
  755. {
  756. if (!m_Horizontal)
  757. position.x = m_Content.anchoredPosition.x;
  758. if (!m_Vertical)
  759. position.y = m_Content.anchoredPosition.y;
  760. if (position != m_Content.anchoredPosition)
  761. {
  762. m_Content.anchoredPosition = position;
  763. UpdateBounds();
  764. }
  765. }
  766. protected virtual void LateUpdate()
  767. {
  768. if (!m_Content)
  769. return;
  770. EnsureLayoutHasRebuilt();
  771. UpdateScrollbarVisibility();
  772. UpdateBounds();
  773. float deltaTime = Time.unscaledDeltaTime;
  774. Vector2 offset = CalculateOffset(Vector2.zero);
  775. if (!m_Dragging && (offset != Vector2.zero || m_Velocity != Vector2.zero))
  776. {
  777. Vector2 position = m_Content.anchoredPosition;
  778. for (int axis = 0; axis < 2; axis++)
  779. {
  780. // Apply spring physics if movement is elastic and content has an offset from the view.
  781. if (m_MovementType == MovementType.Elastic && offset[axis] != 0)
  782. {
  783. float speed = m_Velocity[axis];
  784. position[axis] = Mathf.SmoothDamp(m_Content.anchoredPosition[axis], m_Content.anchoredPosition[axis] + offset[axis], ref speed, m_Elasticity, Mathf.Infinity, deltaTime);
  785. m_Velocity[axis] = speed;
  786. }
  787. // Else move content according to velocity with deceleration applied.
  788. else if (m_Inertia)
  789. {
  790. m_Velocity[axis] *= Mathf.Pow(m_DecelerationRate, deltaTime);
  791. if (Mathf.Abs(m_Velocity[axis]) < 1)
  792. m_Velocity[axis] = 0;
  793. position[axis] += m_Velocity[axis] * deltaTime;
  794. }
  795. // If we have neither elaticity or friction, there shouldn't be any velocity.
  796. else
  797. {
  798. m_Velocity[axis] = 0;
  799. }
  800. }
  801. if (m_Velocity != Vector2.zero)
  802. {
  803. if (m_MovementType == MovementType.Clamped)
  804. {
  805. offset = CalculateOffset(position - m_Content.anchoredPosition);
  806. position += offset;
  807. }
  808. SetContentAnchoredPosition(position);
  809. }
  810. }
  811. //Clamped 模式 三帧后强制对齐(确保加载后)在iphonex适配下启用
  812. if(m_bClampedMove)
  813. {
  814. if (m_nFrame != 0)
  815. m_nFrame -= 1;
  816. if (m_MovementType == MovementType.Clamped && offset.y != 0.0f && m_nFrame == 0)
  817. {
  818. Vector2 v2Postion = m_Content.anchoredPosition + offset;
  819. SetContentAnchoredPosition(v2Postion);
  820. m_bClampedMove = false;
  821. }
  822. }
  823. if (m_Dragging && m_Inertia)
  824. {
  825. Vector3 newVelocity = (m_Content.anchoredPosition - m_PrevPosition) / deltaTime;
  826. m_Velocity = Vector3.Lerp(m_Velocity, newVelocity, deltaTime * 10);
  827. }
  828. if (m_ViewBounds != m_PrevViewBounds || m_ContentBounds != m_PrevContentBounds || m_Content.anchoredPosition != m_PrevPosition)
  829. {
  830. UpdateScrollbars(offset);
  831. m_OnValueChanged.Invoke(normalizedPosition);
  832. UpdatePrevData();
  833. }
  834. if (dirty && (mMovePos > 0 || force) && content.childCount >= mContentCount)
  835. {
  836. if (mMovePos == totalCount - 1)
  837. {
  838. itemTypeStart = totalCount - content.childCount + 1;
  839. }
  840. else if((mMovePos + content.childCount) >= totalCount -1)
  841. {
  842. itemTypeStart = totalCount - mContentCount;
  843. }
  844. else
  845. itemTypeStart = mMovePos;
  846. RefreshCells();
  847. dirty = false;
  848. mMovePos = 0;
  849. force = false;
  850. }
  851. }
  852. private void UpdatePrevData()
  853. {
  854. if (m_Content == null)
  855. m_PrevPosition = Vector2.zero;
  856. else
  857. m_PrevPosition = m_Content.anchoredPosition;
  858. m_PrevViewBounds = m_ViewBounds;
  859. m_PrevContentBounds = m_ContentBounds;
  860. }
  861. private void UpdateScrollbars(Vector2 offset)
  862. {
  863. if (m_HorizontalScrollbar)
  864. {
  865. //==========LoopScrollRect==========
  866. if (m_ContentBounds.size.x > 0 && totalCount > 0)
  867. {
  868. m_HorizontalScrollbar.size = Mathf.Clamp01((m_ViewBounds.size.x - Mathf.Abs(offset.x)) / m_ContentBounds.size.x * (itemTypeEnd - itemTypeStart) / totalCount);
  869. }
  870. //==========LoopScrollRect==========
  871. else
  872. m_HorizontalScrollbar.size = 1;
  873. m_HorizontalScrollbar.value = horizontalNormalizedPosition;
  874. }
  875. if (m_VerticalScrollbar)
  876. {
  877. //==========LoopScrollRect==========
  878. if (m_ContentBounds.size.y > 0 && totalCount > 0)
  879. {
  880. m_VerticalScrollbar.size = Mathf.Clamp01((m_ViewBounds.size.y - Mathf.Abs(offset.y)) / m_ContentBounds.size.y * (itemTypeEnd - itemTypeStart) / totalCount);
  881. }
  882. //==========LoopScrollRect==========
  883. else
  884. m_VerticalScrollbar.size = 1;
  885. m_VerticalScrollbar.value = verticalNormalizedPosition;
  886. }
  887. }
  888. public Vector2 normalizedPosition
  889. {
  890. get
  891. {
  892. return new Vector2(horizontalNormalizedPosition, verticalNormalizedPosition);
  893. }
  894. set
  895. {
  896. SetNormalizedPosition(value.x, 0);
  897. SetNormalizedPosition(value.y, 1);
  898. }
  899. }
  900. public float horizontalNormalizedPosition
  901. {
  902. get
  903. {
  904. UpdateBounds(false);
  905. //==========LoopScrollRect==========
  906. if(totalCount > 0 && itemTypeEnd > itemTypeStart)
  907. {
  908. //TODO: space
  909. float elementSize = m_ContentBounds.size.x / (itemTypeEnd - itemTypeStart);
  910. float totalSize = elementSize * totalCount;
  911. float offset = m_ContentBounds.min.x - elementSize * itemTypeStart;
  912. if (totalSize <= m_ViewBounds.size.x)
  913. return (m_ViewBounds.min.x > offset) ? 1 : 0;
  914. return (m_ViewBounds.min.x - offset) / (totalSize - m_ViewBounds.size.x);
  915. }
  916. else
  917. return 0.5f;
  918. //==========LoopScrollRect==========
  919. }
  920. set
  921. {
  922. SetNormalizedPosition(value, 0);
  923. }
  924. }
  925. public float verticalNormalizedPosition
  926. {
  927. get
  928. {
  929. UpdateBounds(false);
  930. //==========LoopScrollRect==========
  931. if(totalCount > 0 && itemTypeEnd > itemTypeStart)
  932. {
  933. //TODO: space
  934. float elementSize = m_ContentBounds.size.y / (itemTypeEnd - itemTypeStart);
  935. float totalSize = elementSize * totalCount;
  936. float offset = m_ContentBounds.max.y + elementSize * itemTypeStart;
  937. if (totalSize <= m_ViewBounds.size.y)
  938. return (offset > m_ViewBounds.max.y) ? 1 : 0;
  939. return (offset - m_ViewBounds.max.y) / (totalSize - m_ViewBounds.size.y);
  940. }
  941. else
  942. return 0.5f;
  943. //==========LoopScrollRect==========
  944. }
  945. set
  946. {
  947. SetNormalizedPosition(value, 1);
  948. }
  949. }
  950. private void SetHorizontalNormalizedPosition(float value) { SetNormalizedPosition(value, 0); }
  951. private void SetVerticalNormalizedPosition(float value) { SetNormalizedPosition(value, 1); }
  952. private void SetNormalizedPosition(float value, int axis)
  953. {
  954. //==========LoopScrollRect==========
  955. if (totalCount <= 0 || itemTypeEnd <= itemTypeStart)
  956. return;
  957. //==========LoopScrollRect==========
  958. EnsureLayoutHasRebuilt();
  959. UpdateBounds();
  960. //==========LoopScrollRect==========
  961. Vector3 localPosition = m_Content.localPosition;
  962. float newLocalPosition = localPosition[axis];
  963. if (axis == 0)
  964. {
  965. float elementSize = m_ContentBounds.size.x / (itemTypeEnd - itemTypeStart);
  966. float totalSize = elementSize * totalCount;
  967. float offset = m_ContentBounds.min.x - elementSize * itemTypeStart;
  968. newLocalPosition += m_ViewBounds.min.x - value * (totalSize - m_ViewBounds.size[axis]) - offset;
  969. }
  970. else if(axis == 1)
  971. {
  972. float elementSize = m_ContentBounds.size.y / (itemTypeEnd - itemTypeStart);
  973. float totalSize = elementSize * totalCount;
  974. float offset = m_ContentBounds.max.y + elementSize * itemTypeStart;
  975. newLocalPosition -= offset - value * (totalSize - m_ViewBounds.size.y) - m_ViewBounds.max.y;
  976. }
  977. //==========LoopScrollRect==========
  978. if (Mathf.Abs(localPosition[axis] - newLocalPosition) > 0.01f)
  979. {
  980. localPosition[axis] = newLocalPosition;
  981. m_Content.localPosition = localPosition;
  982. m_Velocity[axis] = 0;
  983. UpdateBounds();
  984. }
  985. }
  986. private static float RubberDelta(float overStretching, float viewSize)
  987. {
  988. return (1 - (1 / ((Mathf.Abs(overStretching) * 0.55f / viewSize) + 1))) * viewSize * Mathf.Sign(overStretching);
  989. }
  990. protected override void OnRectTransformDimensionsChange()
  991. {
  992. SetDirty();
  993. }
  994. private bool hScrollingNeeded
  995. {
  996. get
  997. {
  998. if (Application.isPlaying)
  999. return m_ContentBounds.size.x > m_ViewBounds.size.x + 0.01f;
  1000. return true;
  1001. }
  1002. }
  1003. private bool vScrollingNeeded
  1004. {
  1005. get
  1006. {
  1007. if (Application.isPlaying)
  1008. return m_ContentBounds.size.y > m_ViewBounds.size.y + 0.01f;
  1009. return true;
  1010. }
  1011. }
  1012. public virtual void CalculateLayoutInputHorizontal() { }
  1013. public virtual void CalculateLayoutInputVertical() { }
  1014. public virtual float minWidth { get { return -1; } }
  1015. public virtual float preferredWidth { get { return -1; } }
  1016. public virtual float flexibleWidth { get; private set; }
  1017. public virtual float minHeight { get { return -1; } }
  1018. public virtual float preferredHeight { get { return -1; } }
  1019. public virtual float flexibleHeight { get { return -1; } }
  1020. public virtual int layoutPriority { get { return -1; } }
  1021. public virtual void SetLayoutHorizontal()
  1022. {
  1023. m_Tracker.Clear();
  1024. if (m_HSliderExpand || m_VSliderExpand)
  1025. {
  1026. m_Tracker.Add(this, viewRect,
  1027. DrivenTransformProperties.Anchors |
  1028. DrivenTransformProperties.SizeDelta |
  1029. DrivenTransformProperties.AnchoredPosition);
  1030. // Make view full size to see if content fits.
  1031. viewRect.anchorMin = Vector2.zero;
  1032. viewRect.anchorMax = Vector2.one;
  1033. viewRect.sizeDelta = Vector2.zero;
  1034. viewRect.anchoredPosition = Vector2.zero;
  1035. // Recalculate content layout with this size to see if it fits when there are no scrollbars.
  1036. LayoutRebuilder.ForceRebuildLayoutImmediate(content);
  1037. m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size);
  1038. m_ContentBounds = GetBounds();
  1039. }
  1040. // If it doesn't fit vertically, enable vertical scrollbar and shrink view horizontally to make room for it.
  1041. if (m_VSliderExpand && vScrollingNeeded)
  1042. {
  1043. viewRect.sizeDelta = new Vector2(-(m_VSliderWidth + m_VerticalScrollbarSpacing), viewRect.sizeDelta.y);
  1044. // Recalculate content layout with this size to see if it fits vertically
  1045. // when there is a vertical scrollbar (which may reflowed the content to make it taller).
  1046. LayoutRebuilder.ForceRebuildLayoutImmediate(content);
  1047. m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size);
  1048. m_ContentBounds = GetBounds();
  1049. }
  1050. // If it doesn't fit horizontally, enable horizontal scrollbar and shrink view vertically to make room for it.
  1051. if (m_HSliderExpand && hScrollingNeeded)
  1052. {
  1053. viewRect.sizeDelta = new Vector2(viewRect.sizeDelta.x, -(m_HSliderHeight + m_HorizontalScrollbarSpacing));
  1054. m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size);
  1055. m_ContentBounds = GetBounds();
  1056. }
  1057. // If the vertical slider didn't kick in the first time, and the horizontal one did,
  1058. // we need to check again if the vertical slider now needs to kick in.
  1059. // If it doesn't fit vertically, enable vertical scrollbar and shrink view horizontally to make room for it.
  1060. if (m_VSliderExpand && vScrollingNeeded && viewRect.sizeDelta.x == 0 && viewRect.sizeDelta.y < 0)
  1061. {
  1062. viewRect.sizeDelta = new Vector2(-(m_VSliderWidth + m_VerticalScrollbarSpacing), viewRect.sizeDelta.y);
  1063. }
  1064. }
  1065. public virtual void SetLayoutVertical()
  1066. {
  1067. UpdateScrollbarLayout();
  1068. m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size);
  1069. m_ContentBounds = GetBounds();
  1070. }
  1071. void UpdateScrollbarVisibility()
  1072. {
  1073. if (m_VerticalScrollbar && m_VerticalScrollbarVisibility != ScrollbarVisibility.Permanent && m_VerticalScrollbar.gameObject.activeSelf != vScrollingNeeded)
  1074. m_VerticalScrollbar.gameObject.SetActive(vScrollingNeeded);
  1075. if (m_HorizontalScrollbar && m_HorizontalScrollbarVisibility != ScrollbarVisibility.Permanent && m_HorizontalScrollbar.gameObject.activeSelf != hScrollingNeeded)
  1076. m_HorizontalScrollbar.gameObject.SetActive(hScrollingNeeded);
  1077. }
  1078. void UpdateScrollbarLayout()
  1079. {
  1080. if (m_VSliderExpand && m_HorizontalScrollbar)
  1081. {
  1082. m_Tracker.Add(this, m_HorizontalScrollbarRect,
  1083. DrivenTransformProperties.AnchorMinX |
  1084. DrivenTransformProperties.AnchorMaxX |
  1085. DrivenTransformProperties.SizeDeltaX |
  1086. DrivenTransformProperties.AnchoredPositionX);
  1087. m_HorizontalScrollbarRect.anchorMin = new Vector2(0, m_HorizontalScrollbarRect.anchorMin.y);
  1088. m_HorizontalScrollbarRect.anchorMax = new Vector2(1, m_HorizontalScrollbarRect.anchorMax.y);
  1089. m_HorizontalScrollbarRect.anchoredPosition = new Vector2(0, m_HorizontalScrollbarRect.anchoredPosition.y);
  1090. if (vScrollingNeeded)
  1091. m_HorizontalScrollbarRect.sizeDelta = new Vector2(-(m_VSliderWidth + m_VerticalScrollbarSpacing), m_HorizontalScrollbarRect.sizeDelta.y);
  1092. else
  1093. m_HorizontalScrollbarRect.sizeDelta = new Vector2(0, m_HorizontalScrollbarRect.sizeDelta.y);
  1094. }
  1095. if (m_HSliderExpand && m_VerticalScrollbar)
  1096. {
  1097. m_Tracker.Add(this, m_VerticalScrollbarRect,
  1098. DrivenTransformProperties.AnchorMinY |
  1099. DrivenTransformProperties.AnchorMaxY |
  1100. DrivenTransformProperties.SizeDeltaY |
  1101. DrivenTransformProperties.AnchoredPositionY);
  1102. m_VerticalScrollbarRect.anchorMin = new Vector2(m_VerticalScrollbarRect.anchorMin.x, 0);
  1103. m_VerticalScrollbarRect.anchorMax = new Vector2(m_VerticalScrollbarRect.anchorMax.x, 1);
  1104. m_VerticalScrollbarRect.anchoredPosition = new Vector2(m_VerticalScrollbarRect.anchoredPosition.x, 0);
  1105. if (hScrollingNeeded)
  1106. m_VerticalScrollbarRect.sizeDelta = new Vector2(m_VerticalScrollbarRect.sizeDelta.x, -(m_HSliderHeight + m_HorizontalScrollbarSpacing));
  1107. else
  1108. m_VerticalScrollbarRect.sizeDelta = new Vector2(m_VerticalScrollbarRect.sizeDelta.x, 0);
  1109. }
  1110. }
  1111. private void UpdateBounds(bool updateItems = true)
  1112. {
  1113. m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size);
  1114. m_ContentBounds = GetBounds();
  1115. if (m_Content == null)
  1116. return;
  1117. // ============LoopScrollRect============
  1118. // Don't do this in Rebuild
  1119. if (Application.isPlaying && updateItems && UpdateItems(m_ViewBounds, m_ContentBounds))
  1120. {
  1121. Canvas.ForceUpdateCanvases();
  1122. m_ContentBounds = GetBounds();
  1123. }
  1124. // ============LoopScrollRect============
  1125. // Make sure content bounds are at least as large as view by adding padding if not.
  1126. // One might think at first that if the content is smaller than the view, scrolling should be allowed.
  1127. // However, that's not how scroll views normally work.
  1128. // Scrolling is *only* possible when content is *larger* than view.
  1129. // We use the pivot of the content rect to decide in which directions the content bounds should be expanded.
  1130. // E.g. if pivot is at top, bounds are expanded downwards.
  1131. // This also works nicely when ContentSizeFitter is used on the content.
  1132. Vector3 contentSize = m_ContentBounds.size;
  1133. Vector3 contentPos = m_ContentBounds.center;
  1134. Vector3 excess = m_ViewBounds.size - contentSize;
  1135. if (excess.x > 0)
  1136. {
  1137. contentPos.x -= excess.x * (m_Content.pivot.x - 0.5f);
  1138. contentSize.x = m_ViewBounds.size.x;
  1139. }
  1140. if (excess.y > 0)
  1141. {
  1142. contentPos.y -= excess.y * (m_Content.pivot.y - 0.5f);
  1143. contentSize.y = m_ViewBounds.size.y;
  1144. }
  1145. m_ContentBounds.size = contentSize;
  1146. m_ContentBounds.center = contentPos;
  1147. }
  1148. private readonly Vector3[] m_Corners = new Vector3[4];
  1149. private Bounds GetBounds()
  1150. {
  1151. if (m_Content == null)
  1152. return new Bounds();
  1153. var vMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
  1154. var vMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
  1155. var toLocal = viewRect.worldToLocalMatrix;
  1156. m_Content.GetWorldCorners(m_Corners);
  1157. for (int j = 0; j < 4; j++)
  1158. {
  1159. Vector3 v = toLocal.MultiplyPoint3x4(m_Corners[j]);
  1160. vMin = Vector3.Min(v, vMin);
  1161. vMax = Vector3.Max(v, vMax);
  1162. }
  1163. var bounds = new Bounds(vMin, Vector3.zero);
  1164. bounds.Encapsulate(vMax);
  1165. return bounds;
  1166. }
  1167. private Vector2 CalculateOffset(Vector2 delta)
  1168. {
  1169. Vector2 offset = Vector2.zero;
  1170. if (m_MovementType == MovementType.Unrestricted)
  1171. return offset;
  1172. Vector2 min = m_ContentBounds.min;
  1173. Vector2 max = m_ContentBounds.max;
  1174. if (m_Horizontal)
  1175. {
  1176. min.x += delta.x;
  1177. max.x += delta.x;
  1178. if (min.x > m_ViewBounds.min.x)
  1179. offset.x = m_ViewBounds.min.x - min.x;
  1180. else if (max.x < m_ViewBounds.max.x)
  1181. offset.x = m_ViewBounds.max.x - max.x;
  1182. }
  1183. if (m_Vertical)
  1184. {
  1185. min.y += delta.y;
  1186. max.y += delta.y;
  1187. if (max.y < m_ViewBounds.max.y)
  1188. offset.y = m_ViewBounds.max.y - max.y;
  1189. else if (min.y > m_ViewBounds.min.y)
  1190. offset.y = m_ViewBounds.min.y - min.y;
  1191. }
  1192. return offset;
  1193. }
  1194. protected void SetDirty()
  1195. {
  1196. if (!IsActive())
  1197. return;
  1198. LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
  1199. }
  1200. protected void SetDirtyCaching()
  1201. {
  1202. if (!IsActive())
  1203. return;
  1204. CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
  1205. LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
  1206. }
  1207. #if UNITY_EDITOR
  1208. protected override void OnValidate()
  1209. {
  1210. SetDirtyCaching();
  1211. }
  1212. #endif
  1213. }
  1214. }