大家好,我是阿赵。
之前介绍了滚动复用的基础用法。上一个例子里面,是一个竖向单列的滚动列表展示。这一次来扩展一下用法。如果不知道上一次例子的,可以先往前翻一下,上面有例子的详情、原理解释和代码。
一、 多列的滚动复用
有时候,需要展示的东西很多,需要同时显示多列。比如背包,很多个格子在一行。
其实在昨天的基础上,稍微改一下,就能实现多列的显示。
Unity引擎UI滚动复用3
整体思路还是和单列的例子一样,算出每一个index对应的item所在的位置,然后判断是否在当前显示区域内,然后刷新就行了。
上次计算单列的时候,计算item位置是只算了Y坐标的,而且每个高度是通过item的高度加上space的间距来计算的:
protected virtual void InitData()
{
int count = dataList.Count;
for (int i = 0; i < count; i++)
{
float startPos = i * itemHeight;
if(i>0)
{
startPos += spacing * i;
}
itemPosList.Add(new Vector4(0, startPos,0,startPos+itemHeight));
}
contentHeight = itemHeight*count;
if(count>1)
{
contentHeight += spacing * (count - 1);
}
content.sizeDelta = new Vector2(viewWidth, contentHeight);
}
但如果不是单列的情况,那么我们也不能单纯的计算Y坐标了,要把X坐标也计算进去。
假设我现在需要每行显示的item数量,是根据显示范围自动适配的,方法并不复杂,只需要做一个循环,然后不停的模拟把item放进去,然后判断一下,每一行放了新的item之后,会不会超过显示范围的宽度。如果超过了宽度,就把这个item放到下一行的开头。
修改之后的InitData方法会变成这样:
protected override void InitData()
{
int count = dataList.Count;
for (int i = 0; i < count; i++)
{
float startPos = i * itemHeight;
if(i>0)
{
startPos += spacing * i;
}
itemPosList.Add(new Vector4(0, startPos,0,startPos+itemHeight));
}
contentHeight = itemHeight*count;
if(count>1)
{
contentHeight += spacing * (count - 1);
}
content.sizeDelta = new Vector2(viewWidth, contentHeight);
}
由于一个item的宽度是200,然后间距是5,所以当显示范围的宽度是610的时候,刚刚好可以一行显示3个item:
如果把显示范围缩小一点,比如改为550,一行已经放不下3个了,那么就会自动换行,变成了一行显示2个。
由于这个计算只在初始化的时候算一次而已,所以并不会很复杂。这样做就可以做到自适应背景宽度来显示每行的item数。
如果需求不是自动适应,而是要需要指定每行显示的数量,那就不需要那么麻烦了,直接算每个index对应的行列数,就能得出每个item应该所在的位置了。
二、 大小不定的滚动复用
之前的例子都是固定同样大小的item来显示滚动列表。不过有很多时候,可能会需要用到不一样大小的item混合在同一个滚动列表里面显示,比如这个例子:
Unity引擎UI滚动复用5
每隔多少个item,就会显示一个长条形的item。或者一列里面,会出现不同高度的item。
这个实现的思路其实也是很简单的。回到上面第一个例子,用自动适配的方式,根据显示范围的宽度来决定一行里面需要显示多少个item,然后每一行的高度,是这一行里面所有item中的高度最大值。
所以这时候,item的宽高就不是固定的值了,需要有一个地方可以查找到。比如通过传入的数据里面定义一个类型,然后找到对应的item宽高。
由于我这个只是测试的例子,并没有实际的数据输入的,所以我就取巧一下,设置一个间隔数量spaceItemCount,然后设置2种item的大小,每隔spaceItemCount个item就用一个第二种的item宽高来模拟。
于是,InitData方法会变成这样:
protected override void InitData()
{
int count = dataList.Count;
contentHeight = 0;
float curWidth = 0;
float tempItemWidth = 0;
float tempItemHeight = 0;
float nextItemWidth = 0;
float nextItemHeight = 0;
float maxHeight = 0;
int lastItemType = 1;
for (int i = 0; i < count; i++)
{
tempItemWidth = itemWidth;
tempItemHeight = itemHeight;
if(i%spaceItemCount==0)
{
tempItemWidth = itemWidth2;
tempItemHeight = itemHeight2;
lastItemType = 2;
}
else
{
lastItemType = 1;
}
if(tempItemHeight>maxHeight)
{
maxHeight = tempItemHeight;
}
itemPosList.Add(new Vector4(curWidth, contentHeight, curWidth + tempItemWidth, contentHeight + tempItemHeight));
if(i+1%spaceItemCount==0)
{
nextItemWidth = itemWidth2;
nextItemHeight = itemHeight2;
}
else
{
nextItemWidth = itemWidth;
nextItemHeight = itemHeight;
}
if (curWidth+ tempItemWidth + spacing + nextItemWidth > viewWidth)
{
contentHeight += spacing + maxHeight;
curWidth = 0;
maxHeight = 0;
}
else
{
curWidth += spacing + tempItemWidth;
}
}
if(curWidth>0)
{
if(lastItemType == 1)
{
contentHeight += itemHeight;
}
else
{
contentHeight += itemHeight2;
}
}
content.sizeDelta = new Vector2(viewWidth, contentHeight);
}
由于是适配显示范围的宽度,我这个例子是经过设计,第二种item的宽度是刚好和现实范围一样的。假如宽度是随意的,就会变成这样的效果:
Unity引擎UI滚动复用4
可以看到,最终的效果,还是以一行能放多少个item不会超过显示范围高度为标准,然后每一行的高度,是以那一行高度最大的item为标准。