2016-07-02 21:50:37 +08:00
/// Credit Tomasz Schelenz
2020-07-09 03:38:28 +08:00
/// Sourced from - https://bitbucket.org/SimonDarksideJ/unity-ui-extensions/issues/81/infinite-scrollrect
2016-07-02 21:50:37 +08:00
/// Demo - https://www.youtube.com/watch?v=uVTV7Udx78k - configures automatically. - works in both vertical and horizontal (but not both at the same time) - drag and drop - can be initialized by code (in case you populate your scrollview content from code)
2020-10-15 01:03:49 +08:00
/// Updated by Febo Zodiaco - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/issues/349/magnticinfinitescroll
2016-07-02 21:50:37 +08:00
using System.Collections.Generic ;
namespace UnityEngine.UI.Extensions
{
/// <summary>
/// Infinite scroll view with automatic configuration
///
/// Fields
/// - InitByUSer - in case your scrollrect is populated from code, you can explicitly Initialize the infinite scroll after your scroll is ready
2020-10-15 01:03:49 +08:00
/// by calling Init() method
2016-07-02 21:50:37 +08:00
///
/// Notes
2020-10-15 01:03:49 +08:00
/// - does not work in both vertical and horizontal orientation at the same time.
2016-07-02 21:50:37 +08:00
/// - in order to work it disables layout components and size fitter if present(automatically)
///
/// </summary>
[AddComponentMenu("UI/Extensions/UI Infinite Scroll")]
public class UI_InfiniteScroll : MonoBehaviour
{
//if true user will need to call Init() method manually (in case the contend of the scrollview is generated from code or requires special initialization)
[Tooltip("If false, will Init automatically, otherwise you need to call Init() method")]
public bool InitByUser = false ;
2020-10-20 22:48:07 +08:00
protected ScrollRect _scrollRect ;
2016-07-02 21:50:37 +08:00
private ContentSizeFitter _contentSizeFitter ;
private VerticalLayoutGroup _verticalLayoutGroup ;
private HorizontalLayoutGroup _horizontalLayoutGroup ;
private GridLayoutGroup _gridLayoutGroup ;
2020-10-15 01:03:49 +08:00
protected bool _isVertical = false ;
protected bool _isHorizontal = false ;
2016-07-02 21:50:37 +08:00
private float _disableMarginX = 0 ;
private float _disableMarginY = 0 ;
private bool _hasDisabledGridComponents = false ;
2020-10-15 01:03:49 +08:00
protected List < RectTransform > items = new List < RectTransform > ( ) ;
2016-07-02 21:50:37 +08:00
private Vector2 _newAnchoredPosition = Vector2 . zero ;
//TO DISABLE FLICKERING OBJECT WHEN SCROLL VIEW IS IDLE IN BETWEEN OBJECTS
2021-09-05 22:23:48 +08:00
private Vector2 _threshold = Vector2 . zero ;
2016-07-02 21:50:37 +08:00
private int _itemCount = 0 ;
private float _recordOffsetX = 0 ;
private float _recordOffsetY = 0 ;
2020-10-15 01:03:49 +08:00
protected virtual void Awake ( )
2016-07-02 21:50:37 +08:00
{
if ( ! InitByUser )
Init ( ) ;
}
2020-10-15 01:03:49 +08:00
public virtual void SetNewItems ( ref List < Transform > newItems )
{
if ( _scrollRect ! = null )
{
if ( _scrollRect . content = = null & & newItems = = null )
{
return ;
}
if ( items ! = null )
{
items . Clear ( ) ;
}
for ( int i = _scrollRect . content . childCount - 1 ; i > = 0 ; i - - )
{
Transform child = _scrollRect . content . GetChild ( i ) ;
child . SetParent ( null ) ;
GameObject . DestroyImmediate ( child . gameObject ) ;
}
foreach ( Transform newItem in newItems )
{
newItem . SetParent ( _scrollRect . content ) ;
}
SetItems ( ) ;
}
}
private void SetItems ( )
{
for ( int i = 0 ; i < _scrollRect . content . childCount ; i + + )
{
items . Add ( _scrollRect . content . GetChild ( i ) . GetComponent < RectTransform > ( ) ) ;
}
_itemCount = _scrollRect . content . childCount ;
}
2016-07-02 21:50:37 +08:00
public void Init ( )
{
if ( GetComponent < ScrollRect > ( ) ! = null )
{
_scrollRect = GetComponent < ScrollRect > ( ) ;
_scrollRect . onValueChanged . AddListener ( OnScroll ) ;
_scrollRect . movementType = ScrollRect . MovementType . Unrestricted ;
if ( _scrollRect . content . GetComponent < VerticalLayoutGroup > ( ) ! = null )
{
_verticalLayoutGroup = _scrollRect . content . GetComponent < VerticalLayoutGroup > ( ) ;
}
if ( _scrollRect . content . GetComponent < HorizontalLayoutGroup > ( ) ! = null )
{
_horizontalLayoutGroup = _scrollRect . content . GetComponent < HorizontalLayoutGroup > ( ) ;
}
if ( _scrollRect . content . GetComponent < GridLayoutGroup > ( ) ! = null )
{
_gridLayoutGroup = _scrollRect . content . GetComponent < GridLayoutGroup > ( ) ;
}
if ( _scrollRect . content . GetComponent < ContentSizeFitter > ( ) ! = null )
{
_contentSizeFitter = _scrollRect . content . GetComponent < ContentSizeFitter > ( ) ;
}
_isHorizontal = _scrollRect . horizontal ;
_isVertical = _scrollRect . vertical ;
2021-09-05 22:23:48 +08:00
_threshold = _scrollRect . GetComponent < RectTransform > ( ) . sizeDelta * 0.5f ;
2016-07-02 21:50:37 +08:00
if ( _isHorizontal & & _isVertical )
{
2020-07-09 03:38:28 +08:00
Debug . LogError ( "UI_InfiniteScroll doesn't support scrolling in both directions, please choose one direction (horizontal or vertical)" ) ;
2016-07-02 21:50:37 +08:00
}
2020-10-15 01:03:49 +08:00
SetItems ( ) ;
2016-07-02 21:50:37 +08:00
}
else
{
Debug . LogError ( "UI_InfiniteScroll => No ScrollRect component found" ) ;
}
}
void DisableGridComponents ( )
{
if ( _isVertical )
{
2020-01-19 18:50:39 +08:00
_recordOffsetY = items [ 1 ] . GetComponent < RectTransform > ( ) . anchoredPosition . y - items [ 0 ] . GetComponent < RectTransform > ( ) . anchoredPosition . y ;
if ( _recordOffsetY < 0 )
{
_recordOffsetY * = - 1 ;
}
2020-10-15 01:03:49 +08:00
_disableMarginY = _recordOffsetY * _itemCount / 2 ;
2016-07-02 21:50:37 +08:00
}
if ( _isHorizontal )
{
_recordOffsetX = items [ 1 ] . GetComponent < RectTransform > ( ) . anchoredPosition . x - items [ 0 ] . GetComponent < RectTransform > ( ) . anchoredPosition . x ;
2020-01-19 18:50:39 +08:00
if ( _recordOffsetX < 0 )
{
_recordOffsetX * = - 1 ;
}
2020-10-15 01:03:49 +08:00
_disableMarginX = _recordOffsetX * _itemCount / 2 ;
2016-07-02 21:50:37 +08:00
}
if ( _verticalLayoutGroup )
{
_verticalLayoutGroup . enabled = false ;
}
if ( _horizontalLayoutGroup )
{
_horizontalLayoutGroup . enabled = false ;
}
if ( _contentSizeFitter )
{
_contentSizeFitter . enabled = false ;
}
if ( _gridLayoutGroup )
{
_gridLayoutGroup . enabled = false ;
}
_hasDisabledGridComponents = true ;
}
public void OnScroll ( Vector2 pos )
{
if ( ! _hasDisabledGridComponents )
DisableGridComponents ( ) ;
2021-09-05 22:23:48 +08:00
var firstChild = _scrollRect . content . GetChild ( 0 ) . GetComponent < RectTransform > ( ) ;
var lastChild = _scrollRect . content . GetChild ( _itemCount - 1 ) . GetComponent < RectTransform > ( ) ;
2016-07-02 21:50:37 +08:00
for ( int i = 0 ; i < items . Count ; i + + )
{
if ( _isHorizontal )
{
2021-09-05 22:23:48 +08:00
if ( _scrollRect . transform . InverseTransformPoint ( items [ i ] . gameObject . transform . position ) . x > items [ i ] . sizeDelta . x + _threshold . x & & items [ i ] = = lastChild )
2016-07-02 21:50:37 +08:00
{
2021-09-05 22:23:48 +08:00
//Moving before first child ( slide right)
2016-07-02 21:50:37 +08:00
_newAnchoredPosition = items [ i ] . anchoredPosition ;
2021-09-05 22:23:48 +08:00
_newAnchoredPosition . x = firstChild . anchoredPosition . x - items [ i ] . sizeDelta . x ;
2016-07-02 21:50:37 +08:00
items [ i ] . anchoredPosition = _newAnchoredPosition ;
2021-09-05 22:23:48 +08:00
lastChild . transform . SetAsFirstSibling ( ) ;
2016-07-02 21:50:37 +08:00
}
2021-09-05 22:23:48 +08:00
else if ( _scrollRect . transform . InverseTransformPoint ( items [ i ] . gameObject . transform . position ) . x < - items [ i ] . sizeDelta . x - _threshold . x - 100 & & items [ i ] = = firstChild )
2016-07-02 21:50:37 +08:00
{
2021-09-05 22:23:48 +08:00
//Moving before first child (slide left)
2016-07-02 21:50:37 +08:00
_newAnchoredPosition = items [ i ] . anchoredPosition ;
2021-09-05 22:23:48 +08:00
_newAnchoredPosition . x = lastChild . anchoredPosition . x + lastChild . sizeDelta . x ;
2016-07-02 21:50:37 +08:00
items [ i ] . anchoredPosition = _newAnchoredPosition ;
2021-09-05 22:23:48 +08:00
firstChild . transform . SetAsLastSibling ( ) ;
2016-07-02 21:50:37 +08:00
}
}
if ( _isVertical )
{
2021-09-05 22:23:48 +08:00
if ( _scrollRect . transform . InverseTransformPoint ( items [ i ] . gameObject . transform . position ) . y > items [ i ] . sizeDelta . y + _threshold . y & & items [ i ] = = firstChild )
2016-07-02 21:50:37 +08:00
{
2021-09-05 22:23:48 +08:00
//Moving after last child ( slide up)
2016-07-02 21:50:37 +08:00
_newAnchoredPosition = items [ i ] . anchoredPosition ;
2021-09-05 22:23:48 +08:00
_newAnchoredPosition . y = lastChild . anchoredPosition . y - items [ i ] . sizeDelta . y ;
2016-07-02 21:50:37 +08:00
items [ i ] . anchoredPosition = _newAnchoredPosition ;
2021-09-05 22:23:48 +08:00
firstChild . transform . SetAsLastSibling ( ) ;
2016-07-02 21:50:37 +08:00
}
2021-09-05 22:23:48 +08:00
else if ( _scrollRect . transform . InverseTransformPoint ( items [ i ] . gameObject . transform . position ) . y < - items [ i ] . sizeDelta . y - _threshold . y - 100 & & items [ i ] = = lastChild )
2016-07-02 21:50:37 +08:00
{
2021-09-05 22:23:48 +08:00
//Moving before first child (slidw down)
2016-07-02 21:50:37 +08:00
_newAnchoredPosition = items [ i ] . anchoredPosition ;
2021-09-05 22:23:48 +08:00
_newAnchoredPosition . y = firstChild . anchoredPosition . y + firstChild . sizeDelta . y ;
2016-07-02 21:50:37 +08:00
items [ i ] . anchoredPosition = _newAnchoredPosition ;
2021-09-05 22:23:48 +08:00
lastChild . transform . SetAsFirstSibling ( ) ;
2016-07-02 21:50:37 +08:00
}
}
}
}
}
}