无限滚动的原理:
就是通过固定数量的图片或者其他UI组件来实现不固定的数量的图片,具体的原理就是把图片的左下角与世界左上角的坐标进行对比计算,如果这个距离大于一个图片的长度,那就把这个图片从上面拿到下面来,并且重新加载图片
补充:开始写博客的时候只写了原理,最近因为工作需要,就把代码和工程上传了吧(可能不完善,但是能实现功能,有问题欢迎骚扰)
代码:
/*数据类*/
using System.Collections.Generic;
public class UIData
{
private List<ItemData> itemList;
public UIData()
{
itemList = new List<ItemData>();
for (int i = 1; i < 101; i++)
{
ItemData item = new ItemData
{
data = i.ToString()
};
itemList.Add(item);
}
}
///
/// 获取数据
///
///
public List<ItemData> GetData()
{
return itemList;
}
}
public class ItemData
{
public string data;
}
/*Item管理类*/
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class UIItem : MonoBehaviour
{
private Button btn;
private TextMeshProUGUI text;
private ItemData itemData = null;
private UIItemManager itemManager;
///
/// 初始化Item
///
///
///
public void InitilItem(UIItemManager manager, ItemData data)
{
InitilUI();
itemManager = manager;
itemData = data;
text.text = data.data;
}
///
/// 获取Item数据
///
///
public ItemData GetItemData()
{
return itemData;
}
///
/// 更新Item数据
///
public void UpdateItemData(ItemData data)
{
InitilUI();
itemData = data;
if (text != null)
text.text = data.data;
}
private void InitilUI()
{
btn = transform.Find("Button").GetComponent<Button>();
text = btn.transform.GetChild(0).GetComponent<TextMeshProUGUI>();
btn.onClick.AddListener(BtnClicked);
}
private void BtnClicked()
{
itemManager.ItemBtnClicked(itemData);
}
}
/*UI管理类*/
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
public class UIItemManager : MonoBehaviour
{
public List<UIItem> itemList = new List<UIItem>();
public List<ItemData> dataList = new List<ItemData>();
private ScrollRect scroll;
private Transform content;
private RectTransform scrollRect;
private GridLayoutGroup gridLayoutGroup;
private int itemColumnCount;//列数
private int itemRowCount;//行数
private int dataIndex;
private float scrollYMax;
private float scrollYMin;
private float itemHalfSize;
private float curValue;
private float lastValue;
private void Awake()
{
UIData uiData = new UIData();
dataList = uiData.GetData();
}
private void Start()
{
content = transform.Find("Viewport/Content");
scroll = transform.GetComponent<ScrollRect>();
scrollRect = scroll.GetComponent<RectTransform>();
scrollRect = transform.GetComponent<RectTransform>();
gridLayoutGroup = content.GetComponent<GridLayoutGroup>();
if (itemList.Count <= 0)
{
for (int i = 0; i < content.childCount; i++)
{
itemList.Add(content.GetChild(i).GetComponent<UIItem>());
}
}
itemColumnCount = CalculateColumnCount(scrollRect.rect.width, gridLayoutGroup.padding.left, gridLayoutGroup.padding.right, gridLayoutGroup.spacing.x, gridLayoutGroup.cellSize.x);
itemRowCount = itemList.Count / itemColumnCount;
scrollYMax = scrollRect.rect.yMax + scrollRect.rect.height;
scrollYMin = scrollRect.rect.yMin + scrollRect.rect.height;
itemHalfSize = gridLayoutGroup.cellSize.y / 2;
scroll.onValueChanged.AddListener(OnValueChanged);
InitilData(dataList);
}
///
/// 初始化数据
///
public void InitilData(List<ItemData> list)
{
for (int i = 0; i < itemList.Count; i++)
{
itemList[i].InitilItem(this, dataList[i]);
}
dataIndex = itemList.Count;
}
///
/// 回调
///
///
private void OnValueChanged(Vector2 arg0)
{
curValue = arg0.y;
if (lastValue != 0)
{
if (lastValue > curValue)
{
Debug.Log("下滑");
for (int i = 0; i < itemRowCount; i++)
{
int curIndex = i * itemColumnCount;
int nextIndex = (i + 1) * itemColumnCount;
nextIndex %= itemList.Count;
if (itemList[curIndex].transform.position.y - itemHalfSize > scrollYMax)
{
if (itemList[nextIndex].transform.position.y + itemHalfSize < scrollYMax)
{
UpdateItemsPos(VerticalType.Down, curIndex);
}
}
}
}
if(lastValue <= curValue)
{
Debug.Log("上滑");
for (int i = 0; i < itemRowCount; i++)
{
int curIndex = i * itemColumnCount;
int nextIndex = (i + 1) * itemColumnCount;
nextIndex %= itemList.Count;
if (itemList[curIndex].transform.position.y - itemHalfSize > scrollYMin)
{
if (itemList[nextIndex].transform.position.y + itemHalfSize < scrollYMin)
{
UpdateItemsPos(VerticalType.Up, nextIndex);
}
}
}
}
}
lastValue = curValue;
}
///
/// 更新Item位置
///
///
private void UpdateItemsPos(VerticalType type, int itemIndex)
{
Canvas.ForceUpdateCanvases();
if (type == VerticalType.Up)
{
if (content.GetChild(0).GetComponent<UIItem>().GetItemData().data == dataList[0].data) return;
for (int i = itemColumnCount - 1; i > -1; i--)
{
var index = itemIndex + i;
itemList[index].transform.SetAsFirstSibling();
}
UpdateItemsData(itemIndex, type);
scroll.verticalNormalizedPosition = 0;
}
else if(type == VerticalType.Down)
{
if (UpdateItemsData(itemIndex, type) == false) return;
for (int i = 0; i < itemColumnCount; i++)
{
var index = itemIndex + i;
itemList[index].transform.SetAsLastSibling();
}
scroll.verticalNormalizedPosition = 1;
}
}
///
/// 更新数据
///
private bool UpdateItemsData(int itemIndex,VerticalType type)
{
if (type == VerticalType.Up)
{
var curItemData = gridLayoutGroup.transform.GetChild(5).GetComponent<UIItem>().GetItemData();
var tempIndex = dataList.IndexOf(curItemData);
for (int i = itemColumnCount - 1; i > -1; i--)
{
var index = itemIndex + i;
tempIndex--;
itemList[index].GetComponent<UIItem>().UpdateItemData(dataList[tempIndex]);
}
}
else if (type == VerticalType.Down)
{
for (int i = 0; i < itemColumnCount; i++)
{
var index = itemIndex + i;
if (dataIndex >= dataList.Count) return false;
itemList[index].GetComponent<UIItem>().UpdateItemData(dataList[dataIndex]);
dataIndex++;
}
}
return true;
}
///
/// 计算有多少列
///
/// scrollView的宽度
/// 左边距
/// 右边距
/// Item间距
/// item宽度
///
private int CalculateColumnCount(float width,float left,float right,float space,float size)
{
int count = 0;
var temp = width - (left + right);
count = (int)(temp + space) / (int)(size + space);
return count;
}
public void ItemBtnClicked(ItemData data)
{
Debug.Log("当前点击的Item的数据是:" + data.data);
}
}
///
/// 滑动方式
///
public enum VerticalType
{
Up,
Down
}
没写注释,代码也比较简单,应该没啥问题。
下面是导出的包:
传送门