iyed

Untitled

Apr 3rd, 2020
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.59 KB | None | 0 0
  1. /// Credit BinaryX
  2. /// Sourced from - http://forum.unity3d.com/threads/scripts-useful-4-6-scripts-collection.264161/page-2#post-1945602
  3. /// Updated by ddreaper - removed dependency on a custom ScrollRect script. Now implements drag interfaces and standard Scroll Rect.
  4. /// Update by xesenix - rewrote almost the entire code
  5. /// - configuration for direction move instead of 2 concurrent class (easier to change direction in editor)
  6. /// - supports list layout with horizontal or vertical layout need to match direction with type of layout used
  7. /// - dynamic checks if scrolled list size changes and recalculates anchor positions
  8. /// and item size based on itemsVisibleAtOnce and size of root container
  9. /// if you don't wish to use this auto resize turn of autoLayoutItems
  10. /// - fixed current page made it independent from pivot
  11. /// - replaced pagination with delegate function
  12. using System;
  13. using UnityEngine.EventSystems;
  14.  
  15. namespace UnityEngine.UI.Extensions
  16. {
  17. [ExecuteInEditMode]
  18. [RequireComponent(typeof(ScrollRect))]
  19. [AddComponentMenu("UI/Extensions/Scroll Snap Modified")]
  20. public class scrollSnapModified : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler
  21. {
  22. // needed because of reversed behaviour of axis Y compared to X
  23. // (positions of children lower in children list in horizontal directions grows when in vertical it gets smaller)
  24. public enum ScrollDirection
  25. {
  26. Horizontal,
  27. Vertical
  28. }
  29.  
  30. public delegate void PageSnapChange(int page);
  31.  
  32. public event PageSnapChange onPageChange;
  33.  
  34. public ScrollDirection direction = ScrollDirection.Horizontal;
  35.  
  36. protected ScrollRect scrollRect;
  37.  
  38. protected RectTransform scrollRectTransform;
  39.  
  40. protected Transform listContainerTransform;
  41.  
  42. protected RectTransform rectTransform;
  43.  
  44. int pages;
  45. GridLayoutGroup lg;
  46.  
  47. protected int startingPage = 0;
  48.  
  49. // anchor points to lerp to to see child on certain indexes
  50. protected Vector3[] pageAnchorPositions;
  51.  
  52. protected Vector3 lerpTarget;
  53.  
  54. protected bool lerp;
  55.  
  56. // item list related
  57. protected float listContainerMinPosition;
  58.  
  59. protected float listContainerMaxPosition;
  60.  
  61. protected float listContainerSize;
  62.  
  63. protected RectTransform listContainerRectTransform;
  64.  
  65. protected Vector2 listContainerCachedSize;
  66.  
  67. protected float itemSize;
  68.  
  69. protected int itemsCount = 0;
  70.  
  71. [Tooltip("Button to go to the next page. (optional)")]
  72. public Button nextButton;
  73.  
  74. [Tooltip("Button to go to the previous page. (optional)")]
  75. public Button prevButton;
  76.  
  77. [Tooltip("Number of items visible in one page of scroll frame.")]
  78. [RangeAttribute(1, 100)]
  79. public int itemsVisibleAtOnce = 1;
  80.  
  81. [Tooltip("Sets minimum width of list items to 1/itemsVisibleAtOnce.")]
  82. public bool autoLayoutItems = true;
  83.  
  84. [Tooltip("If you wish to update scrollbar numberOfSteps to number of active children on list.")]
  85. public bool linkScrolbarSteps = false;
  86.  
  87. [Tooltip("If you wish to update scrollrect sensitivity to size of list element.")]
  88. public bool linkScrolrectScrollSensitivity = false;
  89.  
  90. public Boolean useFastSwipe = true;
  91.  
  92. public int fastSwipeThreshold = 100;
  93.  
  94. // drag related
  95. protected bool startDrag = true;
  96.  
  97. protected Vector3 positionOnDragStart = new Vector3();
  98.  
  99. protected int pageOnDragStart;
  100.  
  101. protected bool fastSwipeTimer = false;
  102.  
  103. protected int fastSwipeCounter = 0;
  104.  
  105. protected int fastSwipeTarget = 10;
  106.  
  107. // Use this for initialization
  108. void Awake()
  109. {
  110. lerp = false;
  111. lg = GetComponentInChildren<GridLayoutGroup>();
  112. scrollRect = gameObject.GetComponent<ScrollRect>();
  113. scrollRectTransform = gameObject.GetComponent<RectTransform>();
  114. listContainerTransform = scrollRect.content;
  115. listContainerRectTransform = listContainerTransform.GetComponent<RectTransform>();
  116.  
  117. rectTransform = listContainerTransform.gameObject.GetComponent<RectTransform>();
  118. UpdateListItemsSize();
  119. UpdateListItemPositions();
  120.  
  121. PageChanged(CurrentPage());
  122.  
  123. if (nextButton)
  124. {
  125. nextButton.GetComponent<Button>().onClick.AddListener(() =>
  126. {
  127. NextScreen();
  128. });
  129. }
  130.  
  131. if (prevButton)
  132. {
  133. prevButton.GetComponent<Button>().onClick.AddListener(() =>
  134. {
  135. PreviousScreen();
  136. });
  137. }
  138. }
  139.  
  140. void Start()
  141. {
  142. Awake();
  143. }
  144.  
  145. public void UpdateListItemsSize()
  146. {
  147. float size = 0;
  148. float currentSize = 0;
  149. if (direction == scrollSnapModified.ScrollDirection.Horizontal)
  150. {
  151. size = scrollRectTransform.rect.width / itemsVisibleAtOnce;
  152. currentSize = listContainerRectTransform.rect.width / itemsCount;
  153. }
  154. else
  155. {
  156. size = scrollRectTransform.rect.height / itemsVisibleAtOnce;
  157. currentSize = listContainerRectTransform.rect.height / itemsCount;
  158. }
  159.  
  160. itemSize = size;
  161.  
  162. if (linkScrolrectScrollSensitivity)
  163. {
  164. scrollRect.scrollSensitivity = itemSize;
  165. }
  166.  
  167. if (autoLayoutItems && currentSize != size && itemsCount > 0)
  168. {
  169. if (direction == scrollSnapModified.ScrollDirection.Horizontal)
  170. {
  171. foreach (var tr in listContainerTransform)
  172. {
  173. GameObject child = ((Transform)tr).gameObject;
  174. if (child.activeInHierarchy)
  175. {
  176. var childLayout = child.GetComponent<LayoutElement>();
  177.  
  178. if (childLayout == null)
  179. {
  180. childLayout = child.AddComponent<LayoutElement>();
  181. }
  182.  
  183. childLayout.minWidth = itemSize;
  184. }
  185. }
  186. }
  187. else
  188. {
  189. foreach (var tr in listContainerTransform)
  190. {
  191. GameObject child = ((Transform)tr).gameObject;
  192. if (child.activeInHierarchy)
  193. {
  194. var childLayout = child.GetComponent<LayoutElement>();
  195.  
  196. if (childLayout == null)
  197. {
  198. childLayout = child.AddComponent<LayoutElement>();
  199. }
  200.  
  201. childLayout.minHeight = itemSize;
  202. }
  203. }
  204. }
  205. }
  206. }
  207.  
  208. public void UpdateListItemPositions()
  209. {
  210. if (!listContainerRectTransform.rect.size.Equals(listContainerCachedSize))
  211. {
  212. // checking how many children of list are active
  213. int activeCount = 0;
  214.  
  215. foreach (var tr in listContainerTransform)
  216. {
  217. if (((Transform)tr).gameObject.activeInHierarchy)
  218. {
  219. activeCount++;
  220. }
  221. }
  222. // if anything changed since last check reinitialize anchors list
  223. itemsCount = 0;
  224. Array.Resize(ref pageAnchorPositions, activeCount);
  225.  
  226. if (activeCount > 0)
  227. {
  228. pages = Mathf.Max(activeCount - itemsVisibleAtOnce + 1, 1);
  229.  
  230. if (direction == ScrollDirection.Horizontal)
  231. {
  232. // looking for list spanning range min/max
  233. scrollRect.horizontalNormalizedPosition = 0;
  234. listContainerMaxPosition = listContainerTransform.localPosition.x;
  235. scrollRect.horizontalNormalizedPosition = 1;
  236. listContainerMinPosition = listContainerTransform.localPosition.x;
  237.  
  238. listContainerSize = listContainerMaxPosition - listContainerMinPosition;
  239.  
  240. for (var i = 0; i < pages; i++)
  241. {
  242. float extra = 0;
  243. extra = lg.spacing.x*i;
  244. pageAnchorPositions[i] = new Vector3(
  245. listContainerMaxPosition - itemSize * i - extra,
  246. listContainerTransform.localPosition.y,
  247. listContainerTransform.localPosition.z
  248. );
  249. }
  250. }
  251. else
  252. {
  253. //Debug.Log ("-------------looking for list spanning range----------------");
  254. // looking for list spanning range
  255. scrollRect.verticalNormalizedPosition = 1;
  256. listContainerMinPosition = listContainerTransform.localPosition.y;
  257. scrollRect.verticalNormalizedPosition = 0;
  258. listContainerMaxPosition = listContainerTransform.localPosition.y;
  259.  
  260. listContainerSize = listContainerMaxPosition - listContainerMinPosition;
  261.  
  262. for (var i = 0; i < pages; i++)
  263. {
  264. pageAnchorPositions[i] = new Vector3(
  265. listContainerTransform.localPosition.x,
  266. listContainerMinPosition + itemSize * i,
  267. listContainerTransform.localPosition.z
  268. );
  269. }
  270. }
  271.  
  272. UpdateScrollbar(linkScrolbarSteps);
  273. startingPage = Mathf.Min(startingPage, pages);
  274. ResetPage();
  275. }
  276.  
  277. if (itemsCount != activeCount)
  278. {
  279. PageChanged(CurrentPage());
  280. }
  281.  
  282. itemsCount = activeCount;
  283. listContainerCachedSize.Set(listContainerRectTransform.rect.size.x, listContainerRectTransform.rect.size.y);
  284. }
  285.  
  286. }
  287.  
  288. public void ResetPage()
  289. {
  290. if (direction == ScrollDirection.Horizontal)
  291. {
  292. scrollRect.horizontalNormalizedPosition = pages > 1 ? (float)startingPage / (float)(pages - 1) : 0;
  293. }
  294. else
  295. {
  296. scrollRect.verticalNormalizedPosition = pages > 1 ? (float)(pages - startingPage - 1) / (float)(pages - 1) : 0;
  297. }
  298. }
  299.  
  300. protected void UpdateScrollbar(bool linkSteps)
  301. {
  302. if (linkSteps)
  303. {
  304. if (direction == ScrollDirection.Horizontal)
  305. {
  306. if (scrollRect.horizontalScrollbar != null)
  307. {
  308. scrollRect.horizontalScrollbar.numberOfSteps = pages;
  309. }
  310. }
  311. else
  312. {
  313. if (scrollRect.verticalScrollbar != null)
  314. {
  315. scrollRect.verticalScrollbar.numberOfSteps = pages;
  316. }
  317. }
  318. }
  319. else
  320. {
  321. if (direction == ScrollDirection.Horizontal)
  322. {
  323. if (scrollRect.horizontalScrollbar != null)
  324. {
  325. scrollRect.horizontalScrollbar.numberOfSteps = 0;
  326. }
  327. }
  328. else
  329. {
  330. if (scrollRect.verticalScrollbar != null)
  331. {
  332. scrollRect.verticalScrollbar.numberOfSteps = 0;
  333. }
  334. }
  335. }
  336. }
  337.  
  338. void LateUpdate()
  339. {
  340. UpdateListItemsSize();
  341. UpdateListItemPositions();
  342.  
  343. if (lerp)
  344. {
  345. UpdateScrollbar(false);
  346.  
  347. listContainerTransform.localPosition = Vector3.Lerp(listContainerTransform.localPosition, lerpTarget, 7.5f * Time.deltaTime);
  348.  
  349. if (Vector3.Distance(listContainerTransform.localPosition, lerpTarget) < 0.001f)
  350. {
  351. listContainerTransform.localPosition = lerpTarget;
  352. lerp = false;
  353.  
  354. UpdateScrollbar(linkScrolbarSteps);
  355. }
  356.  
  357. //change the info bullets at the bottom of the screen. Just for visual effect
  358. if (Vector3.Distance(listContainerTransform.localPosition, lerpTarget) < 10f)
  359. {
  360. PageChanged(CurrentPage());
  361. }
  362. }
  363.  
  364. if (fastSwipeTimer)
  365. {
  366. fastSwipeCounter++;
  367. }
  368. }
  369.  
  370. private bool fastSwipe = false; //to determine if a fast swipe was performed
  371.  
  372.  
  373. //Function for switching screens with buttons
  374. public void NextScreen()
  375. {
  376. UpdateListItemPositions();
  377.  
  378. if (CurrentPage() < pages - 1)
  379. {
  380. lerp = true;
  381. lerpTarget = pageAnchorPositions[CurrentPage() + 1];
  382.  
  383. PageChanged(CurrentPage() + 1);
  384. }
  385. }
  386.  
  387. //Function for switching screens with buttons
  388. public void PreviousScreen()
  389. {
  390. UpdateListItemPositions();
  391.  
  392. if (CurrentPage() > 0)
  393. {
  394. lerp = true;
  395. lerpTarget = pageAnchorPositions[CurrentPage() - 1];
  396.  
  397. PageChanged(CurrentPage() - 1);
  398. }
  399. }
  400.  
  401. //Because the CurrentScreen function is not so reliable, these are the functions used for swipes
  402. private void NextScreenCommand()
  403. {
  404. if (pageOnDragStart < pages - 1)
  405. {
  406. int targetPage = Mathf.Min(pages - 1, pageOnDragStart + itemsVisibleAtOnce);
  407. lerp = true;
  408.  
  409. lerpTarget = pageAnchorPositions[targetPage];
  410.  
  411. PageChanged(targetPage);
  412. }
  413. }
  414.  
  415. //Because the CurrentScreen function is not so reliable, these are the functions used for swipes
  416. private void PrevScreenCommand()
  417. {
  418. if (pageOnDragStart > 0)
  419. {
  420. int targetPage = Mathf.Max(0, pageOnDragStart - itemsVisibleAtOnce);
  421. lerp = true;
  422.  
  423. lerpTarget = pageAnchorPositions[targetPage];
  424.  
  425. PageChanged(targetPage);
  426. }
  427. }
  428.  
  429.  
  430. //returns the current screen that the is seeing
  431. public int CurrentPage()
  432. {
  433. float pos;
  434.  
  435. if (direction == ScrollDirection.Horizontal)
  436. {
  437. pos = listContainerMaxPosition - listContainerTransform.localPosition.x;
  438. pos = Mathf.Clamp(pos, 0, listContainerSize);
  439. }
  440. else
  441. {
  442. pos = listContainerTransform.localPosition.y - listContainerMinPosition;
  443. pos = Mathf.Clamp(pos, 0, listContainerSize);
  444. }
  445.  
  446. float page = pos / (itemSize+(lg.spacing.x));
  447.  
  448. return Mathf.Clamp(Mathf.RoundToInt(page), 0, pages);
  449. }
  450.  
  451. public void ChangePage(int page)
  452. {
  453. if (0 <= page && page < pages)
  454. {
  455. lerp = true;
  456.  
  457. lerpTarget = pageAnchorPositions[page];
  458.  
  459. PageChanged(page);
  460. }
  461. }
  462.  
  463. //changes the bullets on the bottom of the page - pagination
  464. private void PageChanged(int currentPage)
  465. {
  466. startingPage = currentPage;
  467.  
  468. if (nextButton)
  469. {
  470. nextButton.interactable = currentPage < pages - 1;
  471. }
  472.  
  473. if (prevButton)
  474. {
  475. prevButton.interactable = currentPage > 0;
  476. }
  477.  
  478. if (onPageChange != null)
  479. {
  480. onPageChange(currentPage);
  481. }
  482. }
  483.  
  484. #region Interfaces
  485. public void OnBeginDrag(PointerEventData eventData)
  486. {
  487. UpdateScrollbar(false);
  488.  
  489. fastSwipeCounter = 0;
  490. fastSwipeTimer = true;
  491.  
  492. positionOnDragStart = eventData.position;
  493. pageOnDragStart = CurrentPage();
  494. }
  495.  
  496. public void OnEndDrag(PointerEventData eventData)
  497. {
  498. startDrag = true;
  499. float change = 0;
  500.  
  501. if (direction == ScrollDirection.Horizontal)
  502. {
  503. change = positionOnDragStart.x - eventData.position.x;
  504. }
  505. else
  506. {
  507. change = -positionOnDragStart.y + eventData.position.y;
  508. }
  509.  
  510. if (useFastSwipe)
  511. {
  512. fastSwipe = false;
  513. fastSwipeTimer = false;
  514.  
  515. if (fastSwipeCounter <= fastSwipeTarget)
  516. {
  517. if (Math.Abs(change) > fastSwipeThreshold)
  518. {
  519. fastSwipe = true;
  520. }
  521. }
  522. if (fastSwipe)
  523. {
  524. if (change > 0)
  525. {
  526. NextScreenCommand();
  527. }
  528. else
  529. {
  530. PrevScreenCommand();
  531. }
  532. }
  533. else
  534. {
  535. lerp = true;
  536. lerpTarget = pageAnchorPositions[CurrentPage()];
  537. }
  538. }
  539. else
  540. {
  541. lerp = true;
  542. lerpTarget = pageAnchorPositions[CurrentPage()];
  543. }
  544. }
  545.  
  546. public void OnDrag(PointerEventData eventData)
  547. {
  548. lerp = false;
  549.  
  550. if (startDrag)
  551. {
  552. OnBeginDrag(eventData);
  553. startDrag = false;
  554. }
  555. }
  556. #endregion
  557. }
  558. }
Add Comment
Please, Sign In to add comment