在游戏开发中,经常会遇到需要展示大量数据的情况,例如排行榜、背包等。为了优化显示效果和性能,一个常见的做法是使用无限滑动列表(Infinite Scroll View)。本文将详细解析如何实现无限滑动列表。
无限滑动列表的基本原理是,通过动态加载和回收Item的方式,实现滑动时只创建和显示可见的Item,大大减少了内存开销和渲染性能。
无限滑动列表的实现思路如下:
下面将具体介绍实现无限滑动列表的主要步骤:
初始化Init 首先,我们需要在脚本中声明一些变量和属性,用来控制滑动列表的显示和行为。在Init方法中,我们需要获取滑动框的组件,设置布局,设置Content的大小,并实例化固定数量的Item,这里使用了一个itemPrefab作为Item的模板。
处理滑动OnScroll 在OnScroll方法中,我们需要根据滑动的距离和速度,判断是否需要创建或销毁Item,以及设置其位置和显示内容。这里需要根据滑动的方向(水平或竖直)来做相应的处理。在滑动过程中,我们通过改变Item的位置和显示内容来实现无限滑动的效果。
设置Item的位置和显示内容 通过SetPos方法,我们可以设置Item的位置。其中,根据滑动的方向(水平或竖直),设置Item的锚点位置和偏移量。
外部调用 提供了一些外部调用的方法,用于设置显示内容、设置数据总数量和销毁所有的Item。通过SetShow方法,我们可以自定义Item的显示内容。通过SetTotalCount方法,我们可以设置数据的总数量。通过DestoryAll方法,我们可以销毁所有的Item,以便重置滑动列表。
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
///
/// 无限滑动列表
///
public class InfiniteCrollView : MonoBehaviour
{
private ScrollRect scrollRect;//滑动框组件
private RectTransform content;//滑动框的Content
private GridLayoutGroup layout;//布局组件
[Header("滑动类型")]
public ScrollType scrollType;
[Header("固定的Item数量")]
public int fixedCount;
[Header("Item的预制体")]
public GameObject itemPrefab;
private int totalCount;//总的数据数量
private List dataList = new List();//数据实体列表
private int headIndex;//头下标
private int tailIndex;//尾下标
private Vector2 firstItemAnchoredPos;//第一个Item的锚点坐标
#region Init
///
/// 实例化Item
///
private void InitItem()
{
for (int i = 0; i < fixedCount; i++)
{
GameObject tempItem = Instantiate(itemPrefab, content);
dataList.Add(tempItem.GetComponent());
SetShow(tempItem.GetComponent(), i);
}
}
///
/// 设置Content大小
///
private void SetContentSize()
{
int h;
int v;
if (scrollType == ScrollType.Horizontal)
{
h = totalCount;
v = 1;
}
else
{
h = 1;
v = totalCount;
}
content.sizeDelta = new Vector2
(
layout.padding.left + layout.padding.right + h * (layout.cellSize.x + layout.spacing.x) - layout.spacing.x - transform.GetComponent().rect.width+10,//10是一个调整数为了防止最后一个item显示正常可以按需调整
layout.padding.top + layout.padding.bottom + v * (layout.cellSize.y + layout.spacing.y) - layout.spacing.y
);
}
///
/// 设置布局
///
private void SetLayout()
{
layout.startCorner = GridLayoutGroup.Corner.UpperLeft;
layout.startAxis = GridLayoutGroup.Axis.Horizontal;
layout.childAlignment = TextAnchor.UpperLeft;
layout.constraintCount = 1;
if (scrollType == ScrollType.Horizontal)
{
scrollRect.horizontal = true;
scrollRect.vertical = false;
layout.constraint = GridLayoutGroup.Constraint.FixedRowCount;
}
else if (scrollType == ScrollType.Vertical)
{
scrollRect.horizontal = false;
scrollRect.vertical = true;
layout.constraint = GridLayoutGroup.Constraint.FixedColumnCount;
}
}
///
/// 得到第一个数据的锚点位置
///
private void GetFirstItemAnchoredPos()
{
firstItemAnchoredPos = new Vector2
(
layout.padding.left + layout.cellSize.x / 2,
-layout.padding.top - layout.cellSize.y / 2
);
}
#endregion
#region Main
///
/// 滑动中
///
private void OnScroll(Vector2 v)
{
if (dataList.Count == 0)
{
Debug.LogWarning("先调用SetTotalCount方法设置数据总数量再调用Init方法进行初始化");
return;
}
if (scrollType == ScrollType.Vertical)
{
//向上滑
while (content.anchoredPosition.y >= layout.padding.top + (headIndex + 1) * (layout.cellSize.y + layout.spacing.y)
&& tailIndex != totalCount - 1)
{
//将数据列表中的第一个元素移动到最后一个
RectTransform item = dataList[0];
dataList.Remove(item);
dataList.Add(item);
//设置位置
SetPos(item, tailIndex + 1);
//设置显示
SetShow(item, tailIndex + 1);
headIndex++;
tailIndex++;
}
//向下滑
while (content.anchoredPosition.y <= layout.padding.top + headIndex * (layout.cellSize.y + layout.spacing.y)
&& headIndex != 0)
{
//将数据列表中的最后一个元素移动到第一个
RectTransform item = dataList.Last();
dataList.Remove(item);
dataList.Insert(0, item);
//设置位置
SetPos(item, headIndex - 1);
//设置显示
SetShow(item, headIndex - 1);
headIndex--;
tailIndex--;
}
}
else if (scrollType == ScrollType.Horizontal)
{
//向左滑
while (content.anchoredPosition.x <= -layout.padding.left - (headIndex + 1) * (layout.cellSize.x + layout.spacing.x)
&& tailIndex != totalCount - 1)
{
//将数据列表中的第一个元素移动到最后一个
RectTransform item = dataList[0];
dataList.Remove(item);
dataList.Add(item);
//设置位置
SetPos(item, tailIndex + 1);
//设置显示
SetShow(item, tailIndex + 1);
headIndex++;
tailIndex++;
}
//向右滑
while (content.anchoredPosition.x >= -layout.padding.left - headIndex * (layout.cellSize.x + layout.spacing.x)
&& headIndex != 0)
{
//将数据列表中的最后一个元素移动到第一个
RectTransform item = dataList.Last();
dataList.Remove(item);
dataList.Insert(0, item);
//设置位置
SetPos(item, headIndex - 1);
//设置显示
SetShow(item, headIndex - 1);
headIndex--;
tailIndex--;
}
}
}
#endregion
#region Tool
///
/// 设置位置
///
private void SetPos(RectTransform trans, int index)
{
if (scrollType == ScrollType.Horizontal)
{
trans.anchoredPosition = new Vector2
(
index == 0 ? layout.padding.left + firstItemAnchoredPos.x :
layout.padding.left + firstItemAnchoredPos.x + index * (layout.cellSize.x + layout.spacing.x),
firstItemAnchoredPos.y
);
}
else if (scrollType == ScrollType.Vertical)
{
trans.anchoredPosition = new Vector2
(
firstItemAnchoredPos.x,
index == 0 ? -layout.padding.top + firstItemAnchoredPos.y :
-layout.padding.top + firstItemAnchoredPos.y - index * (layout.cellSize.y + layout.spacing.y)
);
}
}
#endregion
#region 外部调用
///
/// 初始化
///
public void Init()
{
scrollRect = GetComponent();
content = scrollRect.content;
layout = content.GetComponent();
scrollRect.onValueChanged.AddListener((Vector2 v) => OnScroll(v));
//设置布局
SetLayout();
//设置头下标和尾下标
headIndex = 0;
tailIndex = fixedCount - 1;
//设置Content大小
SetContentSize();
//实例化Item
InitItem();
//得到第一个Item的锚点位置
GetFirstItemAnchoredPos();
}
///
/// 设置显示
///
public void SetShow(RectTransform trans, int index)
{
//=====根据需求进行编写
trans.GetComponentInChildren().text = index.ToString();
trans.name = index.ToString();
}
///
/// 设置总的数据数量
///
public void SetTotalCount(int count)
{
totalCount = count;
}
///
/// 销毁所有的元素
///
public void DestoryAll()
{
for (int i = dataList.Count - 1; i >= 0; i--)
{
DestroyImmediate(dataList[i].gameObject);
}
dataList.Clear();
}
#endregion
}
///
/// 滑动类型
///
public enum ScrollType
{
Horizontal,//竖直滑动
Vertical,//水平滑动
}
这篇代码实现了一个无限滑动列表,在Unity引擎中展示。它可以在水平方向或垂直方向上滑动,并根据固定的Item数量在滑动过程中动态加载和复用Item对象,以实现无限滑动的效果。下面将按照步骤逐一解析该代码。
首先,代码定义了一个InfiniteScrollView类,该类继承自MonoBehaviour类,用于管理滑动列表的各项功能。该类主要包含以下成员变量:
接下来,代码定义了一些辅助函数来初始化和操作滑动列表。其中包括:
然后,代码定义了一个OnScroll()函数,用于监听滑动事件,并在滑动过程中处理Item的加载和复用。具体实现如下:
最后,代码提供了一些外部调用的函数,以便进行初始化和设置。它们包括:
通过以上的解析和编写指导,该技术博客将尽可能详细地介绍了无限滑动列表的实现原理和具体操作步骤,帮助读者了解和使用该功能