先上Unity里面的组件的详情
Paste_Image.png
Paste_Image.png
Paste_Image.png
Paste_Image.png
接着是代码
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ScrollViewCircle : MonoBehaviour
{
#region
//滚动的ScrollView//
public ScrollRect m_ScrollRect;
//Mask蒙板,目标是显示区域内的Item,避免在更换Item位置的时候造成直接的视觉误差//
public RectTransform m_ViewRect;
//ScrollView里的Content//
public RectTransform m_Content;
//Item的宽和高//
public Vector2 m_ItemSize;
//Content的padding//
public RectOffset m_ContentPadding;
//预设的物体//
public Item m_ItemPrefab;
public int m_MaxRowCount = 100;
public int m_MaxColumnCount = 3;
#endregion
private int m_ShowMaxRowCount;
private List<ItemData> m_ItemDataList;
Dictionary<int, List<Item>> m_DictToShowingItem = new Dictionary<int, List<Item>>();
//缓存池。
Queue<List<Item>> m_CacheList = new Queue<List<Item>>();
Queue<Item> m_CacheItemList = new Queue<Item>();
//上一次滚动的Index//
int lastIndex;
// Use this for initialization
void Start()
{
SetItemDataList();
m_MaxRowCount = m_ItemDataList.Count / m_MaxColumnCount;
m_ShowMaxRowCount = Mathf.CeilToInt(m_ViewRect.rect.height / m_ItemSize.y) + 1;
m_Content.sizeDelta = new Vector2(m_Content.sizeDelta.x, m_ItemSize.y * m_MaxRowCount);
m_ScrollRect.onValueChanged.AddListener(OnScrollRectValueChange);
lastIndex = -1;
this.OnItemListChange(1);
}
protected virtual void SetItemDataList()
{
if (m_ItemDataList == null)
{
m_MaxRowCount = m_MaxRowCount < 0 ? 50 : m_MaxRowCount;
m_ItemDataList = new List<ItemData>(m_MaxRowCount * m_MaxColumnCount);
for (int i = 0; i < m_MaxRowCount * m_MaxColumnCount; i++)
{
m_ItemDataList.Add(new ItemData() { index = i });
}
}
}
void OnScrollRectValueChange(Vector2 vect)
{
if (vect.y < 0 || vect.y > 1)
{
//Debug.Log("超出范围了,不变化!");
return;
}
//vect.y 是垂直滚动进度,取值范围 [0,1]。
//当vect = 0 时,m_Content.m_Content.anchoredPosition.y = 0。
//当vect = 1 时,m_Content.m_Content.anchoredPosition.y = (m_Content.sizeDelta.y - m_ViewRect.rect.height)。
float y = (1 - vect.y) * (m_Content.sizeDelta.y - m_ViewRect.rect.height);
int index = Mathf.CeilToInt(y / m_ItemSize.y);
this.OnItemListChange(index);
}
void OnItemListChange(int index)
{
if (lastIndex == index)
return;
Debug.Log("index = " + index);
int minIndex = (index);
int maxIndex = (index + m_ShowMaxRowCount);
if (lastIndex < index)
{
//Debug.Log("往上移动!");
for (int key = minIndex - (m_ShowMaxRowCount); key < minIndex; key++)
{
if (m_DictToShowingItem.TryGetValue(key, out List<Item> tempItemList))
{
m_DictToShowingItem.Remove(key);
for (int i = 0; i < tempItemList.Count; i++)
{
EnqueueItem(tempItemList[i]);
}
EnqueueItemList(tempItemList);
}
}
//移除完毕后,添加下方需要增加的Item//
RefreshRowItem(minIndex, maxIndex);
}
else
{
//Debug.Log("往下移动!");
for (int key = maxIndex; key >= maxIndex - 1; key--)
{
if (m_DictToShowingItem.TryGetValue(key, out List<Item> tempItemList))
{
m_DictToShowingItem.Remove(key);
for (int i = 0; i < tempItemList.Count; i++)
{
EnqueueItem(tempItemList[i]);
}
EnqueueItemList(tempItemList);
}
}
//移除完毕后,添加下方需要增加的Item//
RefreshRowItem(minIndex, maxIndex);
}
lastIndex = index;
}
private void RefreshRowItem(int minRow, int maxRow)
{
for (int rowIndex = minRow; rowIndex < maxRow; rowIndex++)
{
if (rowIndex <= 0 || rowIndex > m_MaxRowCount)
continue;
if (!m_DictToShowingItem.ContainsKey(rowIndex))
{
List<Item> tempItemList = PushItemList();
for (int columnIndex = 0; columnIndex < m_MaxColumnCount; columnIndex++)
{
int index = ((rowIndex - 1) * m_MaxColumnCount + columnIndex);
if (index < 0 || index >= m_ItemDataList.Count)
{
continue;
}
var tempItem = PushItem();
var itemData = m_ItemDataList[index];
tempItem.OnInit(itemData);
SetItemPosition(tempItem, rowIndex, columnIndex);
tempItemList.Add(tempItem);
}
m_DictToShowingItem.Add(rowIndex, tempItemList);
}
}
}
private void EnqueueItem(Item item)
{
item.OnClear();
m_CacheItemList.Enqueue(item);
}
private Item PushItem()
{
if (m_CacheItemList.Count == 0)
{
m_CacheItemList.Enqueue(Instantiate(m_ItemPrefab, m_Content) as Item);
}
Item tempItem = m_CacheItemList.Dequeue();
return tempItem;
}
private void EnqueueItemList(List<Item> itemlist)
{
itemlist.Clear();
m_CacheList.Enqueue(itemlist);
}
private List<Item> PushItemList()
{
if (m_CacheList.Count == 0)
{
m_CacheList.Enqueue(new List<Item>());
}
List<Item> result = m_CacheList.Dequeue();
return result;
}
private void SetItemPosition(Item item, int rowIndex, int columnIndex)
{
item.GetComponent<RectTransform>().anchoredPosition = new Vector2(
(columnIndex - ((m_MaxColumnCount - 1) / 2f)) * m_ItemSize.x,
-(rowIndex - 0.5f) * m_ItemSize.y);
item._text.text = ((rowIndex - 1) * m_MaxColumnCount + columnIndex).ToString();
}
}
Item
using UnityEngine;
using UnityEngine.UI;
public class Item : MonoBehaviour
{
public Text _text;
private RectTransform rectTransform;
private void Awake()
{
rectTransform = this.GetComponent<RectTransform>();
rectTransform.anchorMin = new Vector2(0.5f, 1);
rectTransform.anchorMax = new Vector2(0.5f, 1);
rectTransform.pivot = new Vector2(0.5f, 0.5f);
}
public virtual void OnInit(ItemData itemData)
{
_text.text = itemData.index.ToString();
}
public virtual void OnClear()
{
}
}
public class ItemData
{
public int index = 0;
//继承后自定义。
}
暂时就这样,还没实际应用过,不过在demo里测了,感觉还行。