关注

Unity使用UGUI制作无限滑动列表

原理参照上一篇使用NGUI的制作无限滑动列表的文章

Unity 使用NGUI制作无限滑动列表_unity 滑动列表很多物体-CSDN博客

准备工作:

新建一个空物体命名为LoopList,并调整其大小,

并增加Scroll Rect组件(用于滑动)、Rect2D组件(用于裁剪)

新建一个空物体,命名Content,增加布局组件和自适应组件,再将Content的轴点y轴的值设置为1,这样可以让子物体的第一项从列表的顶部的开始排列。

新建一个脚本,命名为LoopScrollList4UGUI,将其挂载到LoopList物体上。

实现(旧):

首先还是来观察Content及其子物体的情况,

从上可以看到,Content的UI坐标的y轴在变化,子物体的局部坐标不变化,因此可以将Content的位置变化作为参考,在Content上移超出一定位置时,将第一个放到最后一个,下移超出一定位置时,将最后一个放到第一个。

怎样操作?

Content的UI坐标位置是从0开始增加的,也就是说上移在ContentUI坐标y轴值大于一个子物体的宽度,下移在小于0,即可进行头部和尾部的子物体的位置变化。

代码如下:


        float currentY = content.anchoredPosition.y;
        // 上移超出一个位置时的处理
        // 向上滚动
        if (currentY > itemHeight)
        {
            Transform firstItem = content.GetChild(0);
            firstItem.SetAsLastSibling();
            content.anchoredPosition = new Vector2(content.anchoredPosition.x, content.anchoredPosition.y - itemHeight);
        }
        // 下移低于一个位置时的处理
        else if (currentY < 0)
        {
            Transform lastItem = content.GetChild(content.childCount - 1);
            lastItem.SetAsFirstSibling();
            content.anchoredPosition = new Vector2(content.anchoredPosition.x, content.anchoredPosition.y + itemHeight);
        }

在什么时候计算?

滑动列表的时候,Scroll Rect的onValueChanged会执行,因此只要在监听这个函数的执行时,就可以计算上述的头尾子物体位置变化。

   // 监听滚动事件
   scrollRect.onValueChanged.AddListener(OnScroll);
   // 滚动事件处理函数
   void OnScroll(Vector2 scrollPosition)
   {
       float currentY = content.anchoredPosition.y;

       // 上移超出一个位置时的处理
       // 向上滚动
       if (currentY > itemHeight)
       {
           Transform firstItem = content.GetChild(0);
           firstItem.SetAsLastSibling();
           content.anchoredPosition = new Vector2(content.anchoredPosition.x, content.anchoredPosition.y - itemHeight);
       }
       // 下移低于一个位置时的处理
       else if (currentY < 0)
       {
           Transform lastItem = content.GetChild(content.childCount - 1);
           lastItem.SetAsFirstSibling();
           content.anchoredPosition = new Vector2(content.anchoredPosition.x, content.anchoredPosition.y + itemHeight);
       }
   }

结果:

实现(新): 

在原来的基础做了一些更改,更改如下:

1.限制content的位置

 content.anchoredPosition = new Vector2(content.anchoredPosition.x,Mathf.Max(contentAnchoredPositionYMin, content.anchoredPosition.y));
 content.anchoredPosition = new Vector2(content.anchoredPosition.x, Mathf.Min(contentAnchoredPositionYMax,content.anchoredPosition.y));

2.设置content的size

content.sizeDelta = new Vector2(content.rect.width,dataList.Count * itemHeight);

3.计算上滑或者下滑,移动Item优化 

 // 上移超出一个位置时的处理
 //向上滚动
 if (topItem.position.y >= topY)
 {
     //超出顶部的距离可以有几个itemHeight的距离
     int times = Mathf.CeilToInt((topItem.position.y - topY) / itemHeight);
     //超出的距离中不满一个itemHeight的部分,需要将这部分在后续计算中处理
     float offset = (topItem.position.y - topY) % itemHeight;
     for (int i = 0; i < times; i++)
     {
         topItem = content.GetChild(topIdx);
         topItem.position = new Vector3(topItem.position.x, bottomY + (times - i - 1) * itemHeight + offset, topItem.position.z);
         topIdx++;
         topIdx %= (visibleItemCount + 1);
         topItem = content.GetChild(topIdx);
         bottomItem = content.GetChild((topIdx + visibleItemCount) % (visibleItemCount + 1));
     }
 }
 // 下移低于一个位置时的处理
 else if (bottomItem.position.y <= bottomY)
 {
     int times = Mathf.CeilToInt(Mathf.Abs(bottomItem.position.y - bottomY) / itemHeight);
     float offset = Mathf.Abs(bottomItem.position.y - bottomY) % itemHeight;
     for (int i = 0; i < times; i++)
     {
         bottomItem = content.GetChild((topIdx + visibleItemCount) % (visibleItemCount + 1));
         bottomItem.position = new Vector3(bottomItem.position.x, topY - (times - i - 1) * itemHeight - offset, bottomItem.position.z);
         topIdx--;
         if (topIdx < 0)
         {
             topIdx = visibleItemCount;
         }
         topItem = content.GetChild(topIdx);
         bottomItem = content.GetChild((topIdx + visibleItemCount) % (visibleItemCount + 1));
     }
 }

4.更新Item信息

        // 上移超出一个位置时的处理
        //向上滚动
        if (topItem.position.y >= topY)
        {
                ...省略部分代码....
                currentDataoffSet++;
                //根据currentDataoffSet来更新Item的具体信息
                UpdateItem(bottomItem.gameObject, currentDataoffSet + visibleItemCount);
            }
        }
        // 下移低于一个位置时的处理
        else if (bottomItem.position.y <= bottomY)
        {
                ...省略部分代码....
                currentDataoffSet--;
                //根据currentDataoffSet来更新Item的具体信息
                UpdateItem(topItem.gameObject, currentDataoffSet);
            }
        }

结果:

实现(新2):

思路:脚本继承ScrollRect,重写SetContentAnchoredPosition函数,得到content的移动位置,用两帧的差值来改变子物体位置。

转载自CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/weixin_50702814/article/details/146191243

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--