| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- /// Credit BinaryX
- /// Sourced from - http://forum.unity3d.com/threads/scripts-useful-4-6-scripts-collection.264161/page-2#post-1945602
- /// Updated by SimonDarksideJ - removed dependency on a custom ScrollRect script. Now implements drag interfaces and standard Scroll Rect.
- using System;
- using UnityEngine.EventSystems;
- namespace UnityEngine.UI.Extensions
- {
- [RequireComponent(typeof(ScrollRect))]
- [AddComponentMenu("Layout/Extensions/Horizontal Scroll Snap")]
- public class HorizontalScrollSnap : ScrollSnapBase
- {
- private bool updated = true;
- void Start()
- {
- _isVertical = false;
- _childAnchorPoint = new Vector2(0, 0.5f);
- _currentPage = StartingScreen;
- panelDimensions = gameObject.GetComponent<RectTransform>().rect;
- UpdateLayout();
- }
- void Update()
- {
- updated = false;
- if (!_lerp && (_scroll_rect.velocity == Vector2.zero && _scroll_rect.inertia))
- {
- if (!_settled && !_pointerDown)
- {
- if (!IsRectSettledOnaPage(_screensContainer.anchoredPosition))
- {
- ScrollToClosestElement();
- }
- }
- return;
- }
- else if (_lerp)
- {
- _screensContainer.anchoredPosition = Vector3.Lerp(_screensContainer.anchoredPosition, _lerp_target, transitionSpeed * (UseTimeScale ? Time.deltaTime : Time.unscaledDeltaTime));
- if (Vector3.Distance(_screensContainer.anchoredPosition, _lerp_target) < 0.2f)
- {
- _screensContainer.anchoredPosition = _lerp_target;
- _lerp = false;
- EndScreenChange();
- }
- }
- if (UseHardSwipe) return;
- CurrentPage = GetPageforPosition(_screensContainer.anchoredPosition);
- //If the container is moving check if it needs to settle on a page
- if (!_pointerDown)
- {
- if (_scroll_rect.velocity.x > 0.01 || _scroll_rect.velocity.x < -0.01)
- {
- //if the pointer is released and is moving slower than the threshold, then just land on a page
- if (IsRectMovingSlowerThanThreshold(0))
- {
- ScrollToClosestElement();
- }
- }
- }
- }
- private bool IsRectMovingSlowerThanThreshold(float startingSpeed)
- {
- return (_scroll_rect.velocity.x > startingSpeed && _scroll_rect.velocity.x < SwipeVelocityThreshold) ||
- (_scroll_rect.velocity.x < startingSpeed && _scroll_rect.velocity.x > -SwipeVelocityThreshold);
- }
- public void DistributePages()
- {
- _screens = _screensContainer.childCount;
- _scroll_rect.horizontalNormalizedPosition = 0;
- float _offset = 0;
- float _dimension = 0;
- Rect panelDimensions = gameObject.GetComponent<RectTransform>().rect;
- float currentXPosition = 0;
- var pageStepValue = _childSize = (int)panelDimensions.width * ((PageStep == 0) ? 3 : PageStep);
- for (int i = 0; i < _screensContainer.transform.childCount; i++)
- {
- RectTransform child = _screensContainer.transform.GetChild(i).gameObject.GetComponent<RectTransform>();
- currentXPosition = _offset + i * pageStepValue;
- child.sizeDelta = new Vector2(panelDimensions.width, panelDimensions.height);
- child.anchoredPosition = new Vector2(currentXPosition, 0f);
- child.anchorMin = child.anchorMax = child.pivot = _childAnchorPoint;
- }
- _dimension = currentXPosition + _offset * -1;
- _screensContainer.GetComponent<RectTransform>().offsetMax = new Vector2(_dimension, 0f);
- }
- /// <summary>
- /// Add a new child to this Scroll Snap and recalculate it's children
- /// </summary>
- /// <param name="GO">GameObject to add to the ScrollSnap</param>
- public void AddChild(GameObject GO)
- {
- AddChild(GO, false);
- }
- /// <summary>
- /// Add a new child to this Scroll Snap and recalculate it's children
- /// </summary>
- /// <param name="GO">GameObject to add to the ScrollSnap</param>
- /// <param name="WorldPositionStays">Should the world position be updated to it's parent transform?</param>
- public void AddChild(GameObject GO, bool WorldPositionStays)
- {
- _scroll_rect.horizontalNormalizedPosition = 0;
- GO.transform.SetParent(_screensContainer, WorldPositionStays);
- InitialiseChildObjectsFromScene();
- DistributePages();
- if (MaskArea)
- UpdateVisible();
- SetScrollContainerPosition();
- }
- /// <summary>
- /// Remove a new child to this Scroll Snap and recalculate it's children
- /// *Note, this is an index address (0-x)
- /// </summary>
- /// <param name="index">Index element of child to remove</param>
- /// <param name="ChildRemoved">Resulting removed GO</param>
- public void RemoveChild(int index, out GameObject ChildRemoved)
- {
- RemoveChild(index, false, out ChildRemoved);
- }
- /// <summary>
- /// Remove a new child to this Scroll Snap and recalculate it's children
- /// *Note, this is an index address (0-x)
- /// </summary>
- /// <param name="index">Index element of child to remove</param>
- /// <param name="WorldPositionStays">If true, the parent-relative position, scale and rotation are modified such that the object keeps the same world space position, rotation and scale as before</param>
- /// <param name="ChildRemoved">Resulting removed GO</param>
- public void RemoveChild(int index, bool WorldPositionStays, out GameObject ChildRemoved)
- {
- ChildRemoved = null;
- if (index < 0 || index > _screensContainer.childCount)
- {
- return;
- }
- _scroll_rect.horizontalNormalizedPosition = 0;
- Transform child = _screensContainer.transform.GetChild(index);
- child.SetParent(null, WorldPositionStays);
- ChildRemoved = child.gameObject;
- InitialiseChildObjectsFromScene();
- DistributePages();
- if (MaskArea)
- UpdateVisible();
- if (_currentPage > _screens - 1)
- {
- CurrentPage = _screens - 1;
- }
- SetScrollContainerPosition();
- }
- /// <summary>
- /// Remove all children from this ScrollSnap
- /// </summary>
- /// <param name="ChildrenRemoved">Array of child GO's removed</param>
- public void RemoveAllChildren(out GameObject[] ChildrenRemoved)
- {
- RemoveAllChildren(false, out ChildrenRemoved);
- }
- /// <summary>
- /// Remove all children from this ScrollSnap
- /// </summary>
- /// <param name="WorldPositionStays">If true, the parent-relative position, scale and rotation are modified such that the object keeps the same world space position, rotation and scale as before</param>
- /// <param name="ChildrenRemoved">Array of child GO's removed</param>
- public void RemoveAllChildren(bool WorldPositionStays, out GameObject[] ChildrenRemoved)
- {
- var _screenCount = _screensContainer.childCount;
- ChildrenRemoved = new GameObject[_screenCount];
- for (int i = _screenCount - 1; i >= 0; i--)
- {
- ChildrenRemoved[i] = _screensContainer.GetChild(i).gameObject;
- ChildrenRemoved[i].transform.SetParent(null, WorldPositionStays);
- }
- _scroll_rect.horizontalNormalizedPosition = 0;
- CurrentPage = 0;
- InitialiseChildObjectsFromScene();
- DistributePages();
- if (MaskArea)
- UpdateVisible();
- }
- private void SetScrollContainerPosition()
- {
- _scrollStartPosition = _screensContainer.anchoredPosition.x;
- _scroll_rect.horizontalNormalizedPosition = (float)(_currentPage) / (_screens - 1);
- OnCurrentScreenChange(_currentPage);
- }
- /// <summary>
- /// used for changing / updating between screen resolutions
- /// </summary>
- public void UpdateLayout()
- {
- _lerp = false;
- DistributePages();
- if (MaskArea)
- UpdateVisible();
- SetScrollContainerPosition();
- OnCurrentScreenChange(_currentPage);
- }
- private void OnRectTransformDimensionsChange()
- {
- if (_childAnchorPoint != Vector2.zero)
- {
- UpdateLayout();
- }
- }
- private void OnEnable()
- {
- InitialiseChildObjectsFromScene();
- DistributePages();
- if (MaskArea)
- UpdateVisible();
- if (JumpOnEnable || !RestartOnEnable)
- SetScrollContainerPosition();
- if (RestartOnEnable)
- GoToScreen(StartingScreen);
- }
- /// <summary>
- /// Release screen to swipe
- /// </summary>
- /// <param name="eventData"></param>
- public override void OnEndDrag(PointerEventData eventData)
- {
- if (updated)
- {
- return;
- }
- // to prevent double dragging, only act on EndDrag once per frame
- updated = true;
- _pointerDown = false;
- if (_scroll_rect.horizontal)
- {
- if (UseSwipeDeltaThreshold && Math.Abs(eventData.delta.x) < SwipeDeltaThreshold)
- {
- ScrollToClosestElement();
- }
- else
- {
- var distance = Vector3.Distance(_startPosition, _screensContainer.anchoredPosition);
- if (UseHardSwipe)
- {
- _scroll_rect.velocity = Vector3.zero;
- if (distance > FastSwipeThreshold)
- {
- if (_startPosition.x - _screensContainer.anchoredPosition.x > 0)
- {
- NextScreen();
- }
- else
- {
- PreviousScreen();
- }
- }
- else
- {
- ScrollToClosestElement();
- }
- }
- else
- {
- if (UseFastSwipe && distance < panelDimensions.width && distance >= FastSwipeThreshold)
- {
- _scroll_rect.velocity = Vector3.zero;
- if (_startPosition.x - _screensContainer.anchoredPosition.x > 0)
- {
- if (_startPosition.x - _screensContainer.anchoredPosition.x > _childSize / 3)
- {
- ScrollToClosestElement();
- }
- else
- {
- NextScreen();
- }
- }
- else
- {
- if (_startPosition.x - _screensContainer.anchoredPosition.x < -_childSize / 3)
- {
- ScrollToClosestElement();
- }
- else
- {
- PreviousScreen();
- }
- }
- }
- }
- }
- }
- }
- }
- }
|