UGUI(十)_无限循环列表
循环列表其实是针对列表组件的优化,如果有1000条数据普通列表会创建1000个item,这样在打开或关闭界面时会有很明显的卡顿现象。所以趁现在有空就尝试做个demo。NGUI的例子中有循环列表的例子,但是要用到项目中还得琢磨一阵子,而且这种功能自己尝试写一写是很好的事情。
先上图:
图中显示到1000条数据的位置,但是注意红框中的item个数它只有11个,所以界面打开关闭也不会有明显的卡顿,原理并不复杂,当滑动条向下滑时,第一个超过显示区域时就移动到最下面;当滑动条向上滑时,最后一个超过显示区域就移动到最上面,然后从数据集合中取出数据进行显示,如此循环即可。
1.先看看封装之后逻辑层的使用
只需要传入【列表的最大数量】和【更新item的回调事件】这两个参数。
刷新界面的代码在封装界面时就可以很自由的进行编写
代码如下:
2.以下是列表的封装
初版代码如下(并不是十分完善只有垂直方向):
注:这种功能就算没有实现也不会成为游戏开发中的瓶颈,因为有很多方式可以避免数据量大引起卡顿的情况,比如使用分页,限制显示数量上限等。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
public delegate void UpdateListItem(Transform item, int index);
public class UIComUnList : MonoBehaviour {
// UI对象绑定
public Transform m_itemParent;
public GameObject m_item;
public Scrollbar m_sb;
// 外部参数设置
public int m_itemWidth; //单元格宽
public int m_itemHeight; //单元格高
public int m_fixedColumnCount; // 固定列数
public int m_fixedColCount; // 固定行数
// 内部私有遍历
private Vector2 m_allItemArea = Vector2.zero; // 当前所有内容高度
private Vector2 m_showArea = Vector2.zero; // 当前显示局域
// 前后的单元格位置
private Vector2 m_firstItemPos = Vector2.zero;
private Vector2 m_lastItemPos = Vector2.zero;
// 数据处理
private int m_listMaxLength = 0;
private int m_curShowStartIndex = 0;
private int m_curShowEndIndex = 0;
// 更新item内容
private UpdateListItem m_updateItem;
private float m_curSbVal = 0; //记录当前值用于获取滑动方向
// 初始化
public void Init(int maxLength, UpdateListItem updateItem)
{
m_showArea = GetComponent().sizeDelta;
m_item.SetActive(false);
m_firstItemPos.y += m_itemHeight;
m_curSbVal = m_sb.value;
m_curShowEndIndex = m_fixedColCount;
m_listMaxLength = maxLength;
m_updateItem = updateItem;
for (int i = 0; i < m_fixedColCount + 1; i++)
{
Transform item = CreateItem(i);
m_updateItem(item, i);
}
}
// 创建item
private Transform CreateItem(int index)
{
Transform item =
((GameObject)GameObject.Instantiate(m_item)).transform;
item.gameObject.SetActive(true);
item.SetParent(m_itemParent);
item.name = index.ToString();
// 1.行
int row = index / m_fixedColumnCount;
// 2.列
int col = index % m_fixedColumnCount;
item.localPosition = new Vector3(col * m_itemWidth, -1 * row * m_itemHeight, 0f);
m_allItemArea.y = (row + 1) * m_itemHeight;
m_lastItemPos.y = -1 * (int)m_allItemArea.y;
return item;
}
// 滑动条值改变时调用
public void OnDragSlider(float val)
{
UpdateListByFloat(m_sb.value * (m_listMaxLength - m_fixedColCount));
}
// 通过一个浮点值滑动列表
public void UpdateListByFloat(float val)
{
UpdateListPos(val);
if (val > m_curSbVal)
{
if (m_curShowEndIndex >= m_listMaxLength - 1) return;
UpdateItemPos(true);
}
else
{
if (m_curShowStartIndex <= 0) return;
UpdateItemPos(false);
}
m_curSbVal = val;
}
// 更新item父节点位置
private void UpdateListPos(float val)
{
// 获取多出来的高度
float excess = 0f;
if (m_allItemArea.y > m_showArea.y)
{
excess = m_allItemArea.y - m_showArea.y;
}
m_itemParent.localPosition = new Vector2(0, excess * val);
}
// 更新item位置
private void UpdateItemPos(bool isDown)
{
if (isDown) // 下滑
{
for (int i = 0; i < m_itemParent.childCount; i++)
{
Transform item = m_itemParent.GetChild(i);
float curPos = item.localPosition.y + m_itemParent.localPosition.y;
if (curPos > m_itemHeight)
{
item.localPosition = new Vector3(0, m_lastItemPos.y, 0);
m_lastItemPos.y -= m_itemHeight;
m_firstItemPos.y -= m_itemHeight;
m_updateItem(item, m_curShowEndIndex + 1);
m_curShowStartIndex ++;
m_curShowEndIndex++;
//break;
}
}
}
else
{
for (int i = m_itemParent.childCount - 1; i >=0 ; i--)
{
Transform item = m_itemParent.GetChild(i);
float curPos = item.localPosition.y + m_itemParent.localPosition.y;
if (curPos < -1 * m_showArea.y)
{
item.localPosition = new Vector3(0, m_firstItemPos.y, 0);
m_firstItemPos.y += m_itemHeight;
m_lastItemPos.y += m_itemHeight;
m_updateItem(item, m_curShowStartIndex - 1);
m_curShowEndIndex --;
m_curShowStartIndex--;
//break;
}
}
}
}
}