UGUI实现ScrollView无限滚动效果

 更新时间:2020年6月25日 10:37  点击:1540

抽空做了一个UGUI的无限滚动的效果。只做了一半(向下无限滚动)。网上也看了很多教程,感觉还是按照自己的思路来写可能比较好。搭建如下:

content节点不添加任何组件。布局组件默认是会重新排版子节点的,所以如果子节点的位置变化,会重新排版,不能达到效果。Size Fitter组件也不加,自己写代码调整Size大小(不调整大小,无法滑动)。

最主要的实现过程就是用Queue来搬运Cell。在向下滚动的过程中(鼠标上滑),顶部滑出View Port的Cell被搬运到底部续上。这点类似于Queue的先见先出原则,再把Dequeue出来的元素添加到末尾,就很类似于ScrollView的无限滚动的原理了。在鼠标上滑的过程中,content的PosY值是一直增加的,所以触发滚动的条件就可以设定为位移之差大于Cell的高度值即可。

 数据的刷新,数据到头之后,不能再次进行滚动轮换了,这里用一组值来记录初始化的一组Cell显示的是数据的哪一段。例如HeadNum和TaiNum。比如用20个Cell显示100条数据。初始化后,HeadNum就是0,TailNum就是19。上滑一行数据后,HeadNum=4,TailNum=23(这里假设是20个Cell排成4列)。

下面是完整代码:

public class UIScrollViewTest : MonoBehaviour {
 
 public RectTransform content;
 public GameObject cell;
 // cell的初始化个数
 public int cellAmount = 0;
 // 鼠标上滑时,存储Cell的Queue。正序存储
 public Queue F_cellQuee = new Queue();
 // 鼠标下滑时,存储Cell的Queue。到序存储
 public Queue B_cellQuee = new Queue();
 // cell的Size
 public Vector2 cellSize = new Vector2(100,100);
 // cell的间隔
 public Vector2 cellOffset = new Vector2(0,0);
 // 列数
 public int columnCount = 0;
 private int rowCount;
 // 上一次content的位置
 public float lastPos;
 // 滚动的次数
 public int loopCount = 0;
 // cell显示的数据段的开头和结尾序号
 public int HeadNum = 0;
 public int TailNum;
 
 public Sprite[] sp;
 public List<Sprite> data;
 
 
 void Start()
 {
  for (int i = 0; i < sp.Length; i++)
  {
   data.Add(sp[i]);
  }
 
  InitialScrollView(data);
  TailNum = cellAmount-1;
  lastPos = content.localPosition.y;
  //Debug.LogError("行数是:::" + rowCount);
 
  //Debug.LogError("+++++++++++++++++ " + (5>>3));
 }
 
 
 void Update()
 {
  // 触发滚动。
  if (content.localPosition.y - lastPos > cellSize.y && data.Count - cellAmount - loopCount*columnCount >0)
  {
   //Debug.LogError("11111111111 " + (data.Count - cellAmount - loopCount * columnCount));
   LoopScrolView(data);
   lastPos = content.localPosition.y;
  }
 }
 
 
 
 
 // 初始化cell
 void InitialScrollView(List<Sprite> data)
 {
  for (int i = 0; i < cellAmount; i++)
  {
   GameObject obj = Instantiate(cell.gameObject);
   obj.transform.SetParent(content);
   obj.name = "cell0" + i.ToString();
   obj.transform.GetChild(0).GetComponent<Text>().text = "cell0"+i.ToString();
   // 显示默认的数据
   obj.GetComponent<Image>().sprite = data[i];
  }
  // 初始化Queue
  for (int i = content.childCount-1; i >= 0; i--)
  {
   B_cellQuee.Enqueue(content.GetChild(i).gameObject);
  }
  for (int i = 0; i < content.childCount; i++)
  {
   F_cellQuee.Enqueue(content.GetChild(i).gameObject);
  }
 
  // 计算行数
  if (cellAmount % columnCount >0)
  {
   rowCount = cellAmount / columnCount + 1;
  } else {
   rowCount = cellAmount / columnCount;
  }
 
  // 排列cell的位置
  int index = 0;
  for (int r = 1; r <= rowCount; r++)
  {
   for (int c = 1; c <= columnCount; c++)
   {
    if (index < cellAmount)
    {
     Vector2 pos = new Vector2(cellSize.x / 2 + (cellSize.x + cellOffset.x) * (c-1), -cellSize.y / 2 - (cellOffset.y + cellSize.y) * (r-1));
     content.GetChild(index).GetComponent<RectTransform>().SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, 0, 100);
     content.GetChild(index).GetComponent<RectTransform>().SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, 0, 100);
     content.GetChild(index).GetComponent<RectTransform>().anchoredPosition = pos;
     index++;
    }
   }
  }
 
  Vector2 v = content.sizeDelta;
  // 初始化content的size
  content.sizeDelta = new Vector2(v.x, rowCount * cellSize.y + cellOffset.y*(rowCount-1));
 }
 
 
 /// 保持content的大小,这里是保持大小为在cell的行数基础上,向下多出bottomCount行的距离
 void SetContentSize(int upperCount, int bottomCount)
 {
  if (content.sizeDelta != new Vector2(content.sizeDelta.x, content.sizeDelta.y + bottomCount * (cellSize.y + cellOffset.y)))
  {
   content.sizeDelta = new Vector2(content.sizeDelta.x, content.sizeDelta.y + bottomCount*(cellSize.y + cellOffset.y));
  }
 }
 
 // 计算顶部的Cell轮换到底部时的位置。以当前最后一行的最后一个Cell的位置为基准计算。
 void SetBottomCellPosition(int index, RectTransform rect, Vector2 pos)
 {
  Vector2 v = Vector2.zero;
  if (cellAmount % columnCount == 0) // 整除。每一行都满的情况。
  {
   float x = pos.x - cellSize.x * (columnCount - index-1) - cellOffset.x * (columnCount-index-1);
   float y = pos.y - cellSize.y - cellOffset.y;
   v = new Vector2(x,y);
  }
  // 出现不满行的情况。例如数据有103个,可以用23个cell来轮换。这样就会出现不满行的情况。
  // 这种情况下是顶部的一行cell顺次接到底部不满的行。例如23号cell后面接1号和2号cell,3号和4号cell填充到第“7”行
  else if (cellAmount % columnCount + index+1<=columnCount) 
  {
   float x = pos.x + cellSize.x * (index+1) + cellOffset.x * (index+1);
   float y = pos.y;
   v = new Vector2(x, y);
  }
  else
  {
   float x = pos.x - cellSize.x * (columnCount - index-1) - cellOffset.x * (columnCount - index-1);
   float y = pos.y - cellSize.y - cellOffset.y;
   v = new Vector2(x, y);
  }
  //Debug.LogError("++++++++++++++ " + pos+ "     "+ v);
  rect.anchoredPosition = v;
  rect.SetAsLastSibling();
 }
 
 // 计算底部的cell轮换到顶部是的位置,基准位置是当前行的第一个cell。
 void SetUpperCellPosition(int index, RectTransform rect, Vector2 pos)
 {
  Vector2 v = Vector2.zero;
  if (cellAmount % columnCount == 0) // 整除
  {
   float x = pos.x + cellSize.x * index + cellOffset.x * index;
   float y = pos.y + cellSize.y + cellOffset.y;
   v = new Vector2(x, y);
  }
  //else if (cellAmount % columnCount + index + 1 <= columnCount)
  //{
  // float x = pos.x + cellSize.x * (index + 1) + cellOffset.x * (index + 1);
  // float y = pos.y;
  // v = new Vector2(x, y);
  //}
  //else
  //{
  // float x = pos.x - cellSize.x * (columnCount - index - 1) - cellOffset.x * (columnCount - index - 1);
  // float y = pos.y - cellSize.y - cellOffset.y;
  // v = new Vector2(x, y);
  //}
  //Debug.LogError("++++++++++++++ " + pos+ "     "+ v);
  rect.anchoredPosition = v;
  rect.SetAsFirstSibling();
 }
 
 
 // 鼠标上滑时,显示当前cell的数据。同时记录数据段的序号递增。
 void ShowRestCellData(Image cell, int index)
 {
  if (TailNum< data.Count-1)
  {
   Debug.LogError("当前的序号是::::" + TailNum);
   TailNum++;
   HeadNum++;
   cell.sprite = data[TailNum];
  }
 }
 
 void ShowPreviousCellData(Image cell, int index)
 {
  if (HeadNum > 0)
  {
   Debug.LogError("当前的序号是::::" + HeadNum);
   TailNum--;
   HeadNum--;
   cell.sprite = data[HeadNum];
  }
 }
 
 
 // 轮换的函数。每次乱换一行的cell。
 void LoopScrolView(List<Sprite> data)
 {
  SetContentSize(0, 1);
  loopCount++;
  RectTransform rect2 = content.GetChild(content.childCount - 1).GetComponent<RectTransform>();
  for (int i = 0; i < columnCount; i++)
  {
   GameObject obj = F_cellQuee.Dequeue() as GameObject;
   RectTransform rect = obj.GetComponent<RectTransform>();
   ShowRestCellData(obj.GetComponent<Image>(), i);
   SetBottomCellPosition(i, rect, rect2.anchoredPosition);
   F_cellQuee.Enqueue(obj);
  }
 }
 
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。

[!--infotagslink--]

相关文章

  • CocosCreator ScrollView优化系列之分帧加载

    这篇文章主要介绍了CocosCreator ScrollView的优化,从分帧加载进行了讲解,对性能优化感兴趣的同学,一定要看一下...2021-04-15
  • Unity3D UGUI实现翻书特效

    这篇文章主要为大家详细介绍了Unity3D UGUI实现翻书特效,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • Unity工具类ScrollView实现拖拽滑动翻页

    这篇文章主要为大家详细介绍了Unity工具类ScrollView实现拖拽滑动翻页,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • Unity3D使用UGUI开发原生虚拟摇杆

    这篇文章主要为大家详细介绍了Unity3D使用UGUI开发原生虚拟摇杆,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • Unity3D UGUI特效之Image高斯模糊效果

    这篇文章主要为大家详细介绍了Unity3D UGUI特效之Image高斯模糊效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • 微信小程序自定义scroll-view的实例代码

    这篇文章主要给大家介绍了关于微信小程序自定义scroll-view的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-02
  • UGUI实现4位验证码输入

    这篇文章主要为大家详细介绍了UGUI实现4位验证码输入,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • iOS UIScrollView和控制器返回手势冲突解决方法

    这篇文章主要介绍了iOS UIScrollView和控制器返回手势冲突解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-04
  • Unity UGUI教程之实现滑页效果

    使用UGUI提供的ScrollRect和ScrollBar组件实现基本滑动以及自己控制每次移动一页来达到滑页的效果。具体实现思路请参考下本教程...2020-06-25
  • UGUI轮播图组件实现方法详解

    这篇文章主要为大家详细介绍了UGUI轮播图组件的实现方法,支持自动轮播、手势切换等功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • Unity UGUI实现卡片椭圆方向滚动

    这篇文章主要为大家详细介绍了UGUI实现卡片椭圆方向滚动效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • UGUI实现随意调整Text中的字体间距

    这篇文章主要为大家详细介绍了UGUI实现随意调整字体间距的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • Unity UGUI通过摇杆控制角色移动

    这篇文章主要为大家详细介绍了Unity3D基于陀螺仪实现VR相机功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • IOS开发之UIScrollView实现图片轮播器的无限滚动

    这篇文章主要介绍了IOS开发之UIScrollView实现图片轮播器的无限滚动的相关资料,需要的朋友可以参考下...2020-04-25
  • Unity UGUI控制text文字间距

    这篇文章主要为大家详细介绍了Unity UGUI控制text文字间距的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • Android 滑动Scrollview标题栏渐变效果(仿京东toolbar)

    这篇文章主要介绍了Android 滑动Scrollview标题栏渐变效果(仿京东toolbar),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-29
  • UGUI绘制动态曲线

    这篇文章主要为大家详细介绍了UGUI绘制动态曲线的具体方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • UGUI ScrollRect实现带按钮翻页支持拖拽

    这篇文章主要为大家详细介绍了UGUI ScrollRect实现带按钮翻页支持拖拽,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • 使用Element的InfiniteScroll 无限滚动组件报错的解决

    这篇文章主要介绍了使用Element的InfiniteScroll 无限滚动组件报错的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-07-27
  • Unity利用UGUI制作提示框效果

    这篇文章主要为大家详细介绍了Unity利用UGUI制作提示框效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-11-03