引言

Unity中对于如排行榜,关卡列表等需要动态生成的列表一般是采用有多少就实例化多少的做法,这样一般情况下是没问题,但如果需要显示很多如上百上千个的话继续采用这种做法会造成内存的浪费,卡顿等。所以此时需要我们编写一套可以随Scroll Rect的滚动来动态调整位置并赋值的算法来满足我们的需求。

正文分析

本文暂时只讨论每个克隆体的width和height一致的情况。思路分为以下三步。

1. 调整Content宽高(content和克隆体的中心点锚点需要设置为左上角方便调整位置。)当滚动列表为垂直滚动时:宽固定为(Content.sizeDelta.x),高则取决于创建的行数;当滚动列表为水平滚动时:宽固定为(Content.sizeDelta.y),宽则取决于创建的列数;

if (verticalOrHorizontal == EVerticalOrHorizontal.Vertical)
{
int creat_count = (rowCount + 2) * columnCount;//需要创建的数量
int totalCreatItemCount = creat_count > m_listCount ? m_listCount : creat_count;//实际需要创建的数量
int rowSum = m_listCount / columnCount + (m_listCount % columnCount > 0 ? 1 : 0);      //计算有多少行,用于计算出总高度
rectContent.sizeDelta = new Vector2(rectContent.sizeDelta.x, m_padding.y + (itemPrefabSizeDelta.y + m_spacing.y) * rowSum);
}
else if (verticalOrHorizontal == EVerticalOrHorizontal.Horizontal)
{
int creat_count = (columnCount + 2) * rowCount;//需要创建的数量
int totalCreatItemCount = creat_count > m_listCount ? m_listCount : creat_count;//实际需要创建的数量
int columnSum = m_listCount / rowCount + (m_listCount % rowCount > 0 ? 1 : 0);//计算有多少列,用于计算出总宽度
rectContent.sizeDelta = new Vector2(m_padding.x + (itemPrefabSizeDelta.x + m_spacing.x) * columnSum, rectContent.sizeDelta.y);
}

 2.  创建克隆体并根据id确定位置: 克隆体的数量需要比屏幕可显示的数量多两行或两列(如果是垂直滚动则为两行,反之为两列):当滚动列表为垂直滚动时:x轴为i与列数取余和item的宽的乘积,y轴为i与列数相除和item的宽的乘积;当滚动列表为水平滚动时反之即可。 确定好位置之后将其id和prefab保存下来供3使用。

private Vector2 GetPos(int i)
{
if (verticalOrHorizontal == EVerticalOrHorizontal.Vertical)
return new Vector2(i % columnCount * (itemPrefabSizeDelta.x + m_spacing.x) + m_padding.x, -i / columnCount * (itemPrefabSizeDelta.y + m_spacing.y) - m_padding.y);
else
return new Vector2(i / rowCount * (itemPrefabSizeDelta.y + m_spacing.x) + m_padding.x, -i % rowCount * (itemPrefabSizeDelta.x + m_spacing.y) - m_padding.y);
}

 

 3.  Scroll Rect滚动动态更换克隆体位置并赋值:根据content坐标可以确定起始id和结束id,再根据2可以将需要更换的克隆体调整到相应的位置。

private int GetStartIndex_Y(float y)
{
if (y <= (itemPrefabSizeDelta.y + m_padding.y))//拉到顶部了
return 0;
if (y >= (rectContent.sizeDelta.y - scrollHeigh - m_padding.y))        //拉到底部了
{
if (m_listCount <= totalCreatItemCount)
return 0;
else
return m_listCount - totalCreatItemCount;
}
return ((int)((y - m_padding.y) / (itemPrefabSizeDelta.y + m_spacing.x)) + ((y - m_padding.y) % (itemPrefabSizeDelta.y + m_spacing.y) > 0 ? 1 : 0) - 1) * columnCount;
}

 

 使用方法

1.将RecyclingScrollRectItem挂在Scroll View上并初始化各属性;

2.将prefab作为content子物体;

3.在需要创建的时机调用RecyclingScrollRectItem. InitList()方法即可。