using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using XLua;
///
/// 高性能ScrollView
///
[RequireComponent(typeof(ScrollRect))]
public class GridScroller : MonoBehaviour
{
public enum Movement
{
Horizontal,
Vertical
}
public delegate void MoveToEndCallback();
public delegate void OnScrollViewItemChanged(Transform trans, int itemIdx);
private List
private Vector2 _cellSize = Vector3.zero;
private int _col;
private HashSet
private Dictionary
private RectTransform _grid;
private bool _hasChanged;
private Stack
private GameObject _itemPrefab;
private Movement _moveType;
private HashSet
private OnScrollViewItemChanged _onNewItemBecomeVisibleCallback;
private int _row;
private ScrollRect _scroller;
private Rect _scrollerRect;
private Vector2 _spacing = Vector3.zero;
private int _totalItemCount;
private int _visibleItemCount;
private float cachedPos;
public MoveToEndCallback moveToEndCallBack;
public bool moveToEndLock;
public Vector2 ItemSize
{
get
{
return _spacing + _cellSize;
}
}
public Movement MoveType
{
get
{
return _moveType;
}
set
{
_moveType = value;
}
}
public RectTransform Grid
{
set
{
_grid = value;
}
}
public GameObject ItemPrefab
{
set
{
_itemPrefab = value;
}
}
private Vector2 CalcPosByIndex(int index)
{
if (_moveType == Movement.Horizontal)
{
return new Vector2(ItemSize.x * (index / _row), -ItemSize.y * (index % _row));
}
return new Vector2(ItemSize.x * (index % _col), -ItemSize.y * (index / _col));
}
private void CheckMoveToEnd()
{
if ((moveToEndCallBack != null) && !moveToEndLock)
{
bool flag = false;
if (_moveType == Movement.Horizontal)
{
if (_grid.rect.width - _scrollerRect.width > 0 && Math.Abs(_grid.anchoredPosition.x) + _scrollerRect.width > _grid.rect.width)
{
flag = true;
}
}
else if (_grid.rect.height - _scrollerRect.height > 0 && Math.Abs(_grid.anchoredPosition.y) + _scrollerRect.height > _grid.rect.height)
{
flag = true;
}
if (flag)
{
moveToEndCallBack();
}
}
}
public void Clear()
{
var enumerator = _currentVisibleItemIdxRTMap.GetEnumerator();
while (enumerator.MoveNext())
{
KeyValuePair
current.Value.gameObject.SetActive(false);
KeyValuePair
_cacheList.Add(pair2.Value);
}
Stack
while (enumerator2.MoveNext())
{
enumerator2.Current.gameObject.SetActive(false);
_cacheList.Add(enumerator2.Current);
}
_itemPool.Clear();
_totalItemCount = 0;
_currentItemIdxSet.Clear();
_currentVisibleItemIdxRTMap.Clear();
_nextVisibleItemSet.Clear();
_scroller.onValueChanged.RemoveAllListeners();
}
public void DisplayItemFromStartIdx(int index)
{
if (index < _totalItemCount)
{
Vector2 vector = CalcPosByIndex(index);
Vector2 vector2 = (_moveType == Movement.Horizontal) ? new Vector2(-vector.x, 0f) : new Vector2(0f, -vector.y);
_grid.anchoredPosition = vector2;
OnScrollValueChanged(Vector2.zero);
}
}
private Transform GetItem()
{
Transform item = null;
if (_cacheList.Count > 0)
{
item = _cacheList[0];
_cacheList.Remove(item);
}
if ((item == null) || (item.gameObject == null))
{
item = AddChild(_grid.gameObject, _itemPrefab).transform;
}
item.gameObject.SetActive(true);
return item;
}
public void Init(OnScrollViewItemChanged onChange, int itemCount, Vector2 normalPosition = new Vector2())
{
InitScroller();
InitCustomGrid();
UpdateCustomGridSizeByItemCount(itemCount, false, normalPosition);
InitChildren(onChange);
}
private void InitChild(RectTransform rt, int idx)
{
rt.anchorMax = new Vector2(0f, 1f);
rt.anchorMin = new Vector2(0f, 1f);
rt.pivot = new Vector2(0f, 1f);
rt.sizeDelta = _cellSize;
rt.anchoredPosition = CalcPosByIndex(idx);
}
private void InitChildren(OnScrollViewItemChanged onChange)
{
_onNewItemBecomeVisibleCallback = onChange;
_visibleItemCount = _col * _row;
if (_visibleItemCount > _totalItemCount)
{
_visibleItemCount = _totalItemCount;
}
for (int i = 0; i != _visibleItemCount; i++)
{
Transform item = GetItem();
InitChild(item.GetComponent
_onNewItemBecomeVisibleCallback(item, i);
_currentItemIdxSet.Add(i);
_currentVisibleItemIdxRTMap.Add(i, item.GetComponent
}
}
private void InitCustomGrid()
{
_cellSize = _grid.GetComponent
_spacing = _grid.GetComponent
_grid.GetComponent
}
private void InitScroller()
{
_scroller = base.GetComponent
_scrollerRect = _scroller.GetComponent
if (_moveType == Movement.Horizontal)
{
_scroller.vertical = false;
_scroller.horizontal = true;
}
else
{
_scroller.vertical = true;
_scroller.horizontal = false;
}
}
public void OnScrollValueChanged(Vector2 normalizedPosition)
{
CheckMoveToEnd();
if (_visibleItemCount != _totalItemCount)
{
int firstVisibleIdx = 0;
if (_moveType == Movement.Horizontal)
{
float num2 = -_grid.anchoredPosition.x;
int num3 = (int) (num2 / ItemSize.x);
firstVisibleIdx = num3 * _row;
}
else
{
int num5 = (int) (_grid.anchoredPosition.y / ItemSize.y);
firstVisibleIdx = num5 * _col;
}
UpdateVisibleItemListByNewStartIdx(firstVisibleIdx);
}
}
public void RefreshCurrent()
{
foreach (int num in _currentItemIdxSet)
{
if ((_onNewItemBecomeVisibleCallback != null) && _currentVisibleItemIdxRTMap.ContainsKey(num))
{
_onNewItemBecomeVisibleCallback(_currentVisibleItemIdxRTMap[num], num);
}
}
}
public void Reset()
{
if (_moveType == Movement.Horizontal)
{
SetX(_grid,0f);
}
else
{
SetY(_grid,0f);
}
UpdateVisibleItemListByNewStartIdx(0);
}
public void ResetSpacing()
{
_cellSize = _grid.GetComponent
_spacing = _grid.GetComponent
}
private void SpawnItemFromPoolByIdx(int spawnItemIdx)
{
if (_itemPool.Count > 0)
{
RectTransform transform = _itemPool.Pop();
transform.anchoredPosition = CalcPosByIndex(spawnItemIdx);
_currentVisibleItemIdxRTMap.Add(spawnItemIdx, transform);
if (_onNewItemBecomeVisibleCallback != null)
{
_onNewItemBecomeVisibleCallback(transform, spawnItemIdx);
}
}
}
public void StopScrollMove()
{
if (null != _scroller)
{
_scroller.StopMovement();
}
}
private void UpdateCustomGridSizeByItemCount(int itemCount,bool moveToEnd,Vector2 normalizedPosition)
{
_totalItemCount = itemCount;
_col = Mathf.RoundToInt((_scrollerRect.width + _spacing.x) / ItemSize.x);
_row = Mathf.RoundToInt((_scrollerRect.height + _spacing.y) / ItemSize.y);
if (_moveType == Movement.Horizontal)
{
_col += 2;
}
else
{
_row += 2;
}
if (_moveType == Movement.Horizontal)
{
_grid.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, Mathf.CeilToInt(((float) _totalItemCount) / ((float) _row)) * ItemSize.x);
if(moveToEnd)
{
Vector2 end = CalcPosByIndex(itemCount - 1);
SetX(_grid, -end.x);
}
else
{
SetX(_grid, 0f);
}
}
else
{
_grid.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, Mathf.CeilToInt(((float) _totalItemCount) / ((float) _col)) * ItemSize.y);
if(moveToEnd)
{
Vector2 end = CalcPosByIndex(itemCount - 1);
SetY(_grid, -end.y);
}
else
{
SetY(_grid, 0f);
}
}
_scroller.onValueChanged.AddListener(new UnityAction
}
public void UpdateGridSize()
{
UpdateCustomGridSizeByItemCount(_totalItemCount, false, new Vector2());
}
public void UpdateItemCount(int count, bool savePos = false, bool forceRefresh = false)
{
if (!forceRefresh && (_totalItemCount == count))
{
RefreshCurrent();
}
else
{
if (savePos)
{
if (_moveType == Movement.Horizontal)
{
cachedPos = _grid.anchoredPosition.x;
}
else
{
cachedPos = _grid.anchoredPosition.y;
}
}
Clear();
UpdateCustomGridSizeByItemCount(count, false, new Vector2());
InitChildren(_onNewItemBecomeVisibleCallback);
if (savePos)
{
if (_moveType == Movement.Horizontal)
{
if (cachedPos < 0f)
{
cachedPos = 0f;
}
if (-cachedPos > (_grid.rect.width - _scrollerRect.width))
{
cachedPos = -(_grid.rect.width - _scrollerRect.width);
}
SetX(_grid,cachedPos);
}
else
{
if (cachedPos < 0f)
{
cachedPos = 0f;
}
if (cachedPos > (_grid.rect.height - _scrollerRect.height))
{
cachedPos = Mathf.Max((float) (_grid.rect.height - _scrollerRect.height), (float) 0f);
}
SetY(_grid,cachedPos);
}
if (forceRefresh)
{
OnScrollValueChanged(new Vector2());
}
}
}
}
public void AddNewItem()
{
int count = _totalItemCount + 1;
if (_moveType == Movement.Horizontal)
{
cachedPos = _grid.anchoredPosition.x;
}
else
{
cachedPos = _grid.anchoredPosition.y;
}
Clear();
UpdateCustomGridSizeByItemCount(count,true, new Vector2());
InitChildren(_onNewItemBecomeVisibleCallback);
//Transform item = _itemPool.Pop();
//InitChild(item.GetComponent
//_currentItemIdxSet.Add(count - 1);
//_currentVisibleItemIdxRTMap.Add(count - 1, item.GetComponent
//_onNewItemBecomeVisibleCallback(item, count - 1);
if (_moveType == Movement.Horizontal)
{
if (cachedPos < 0f)
{
cachedPos = 0f;
}
if (-cachedPos > (_grid.rect.width - _scrollerRect.width))
{
cachedPos = -(_grid.rect.width - _scrollerRect.width);
}
SetX(_grid, cachedPos + ItemSize.x + _spacing.x);
}
else
{
if (cachedPos < 0f)
{
cachedPos = 0f;
}
if (cachedPos > (_grid.rect.height - _scrollerRect.height))
{
cachedPos = Mathf.Max((float)(_grid.rect.height - _scrollerRect.height), (float)0f);
}
SetY(_grid, cachedPos + ItemSize.y);
}
}
private void UpdateVisibleItemListByNewStartIdx(int firstVisibleIdx)
{
_nextVisibleItemSet.Clear();
for (int i = 0; i != _visibleItemCount; i++)
{
if (((i + firstVisibleIdx) < _totalItemCount) && ((i + firstVisibleIdx) >= 0))
{
_nextVisibleItemSet.Add(i + firstVisibleIdx);
}
}
if (!_nextVisibleItemSet.SetEquals(_currentItemIdxSet))
{
IEnumerator
IEnumerator
while (enumerator2.MoveNext())
{
_itemPool.Push(_currentVisibleItemIdxRTMap[enumerator2.Current]);
_currentVisibleItemIdxRTMap.Remove(enumerator2.Current);
}
while (minusSet.MoveNext())
{
SpawnItemFromPoolByIdx(minusSet.Current);
}
HashSet
_currentItemIdxSet = _nextVisibleItemSet;
_nextVisibleItemSet = newSet;
}
}
private void SetX(RectTransform rt, float x)
{
Vector2 anchoredPosition = rt.anchoredPosition;
anchoredPosition.x = x;
rt.anchoredPosition = anchoredPosition;
}
private void SetY(RectTransform rt, float y)
{
Vector2 anchoredPosition = rt.anchoredPosition;
anchoredPosition.y = y;
rt.anchoredPosition = anchoredPosition;
}
private GameObject AddChild(GameObject parent, GameObject child)
{
GameObject go = UnityEngine.Object.Instantiate
go.SetActive(true);
if ((go != null) && (parent != null))
{
Transform transform = go.transform;
transform.SetParent(parent.transform);
transform.localPosition = Vector3.zero;
transform.localRotation = Quaternion.identity;
transform.localScale = Vector3.one;
go.layer = parent.layer;
}
return go;
}
private IEnumerator
{
List
HashSet
while (enumerator.MoveNext())
{
if (!except.Contains(enumerator.Current))
{
list.Add(enumerator.Current);
}
}
return list.GetEnumerator();
}
}
#if UNITY_EDITOR
public static class GridScrollerExporter
{
[LuaCallCSharp]
public static List
{
typeof(ScrollRect),
typeof(GridScroller),
};
[CSharpCallLua]
public static List
{
typeof(GridScroller.OnScrollViewItemChanged),
typeof(GridScroller.MoveToEndCallback),
};
}
#endif