Unity引擎UI滚动列表——滚动复用扩展应用

  大家好,我是阿赵。
  之前介绍了滚动复用的基础用法。上一个例子里面,是一个竖向单列的滚动列表展示。这一次来扩展一下用法。如果不知道上一次例子的,可以先往前翻一下,上面有例子的详情、原理解释和代码。

一、 多列的滚动复用

  有时候,需要展示的东西很多,需要同时显示多列。比如背包,很多个格子在一行。
  其实在昨天的基础上,稍微改一下,就能实现多列的显示。

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为标准。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值