UGUI实现ScrollView无限滚动效果
程序员文章站
2023-12-06 13:13:58
抽空做了一个ugui的无限滚动的效果。只做了一半(向下无限滚动)。网上也看了很多教程,感觉还是按照自己的思路来写可能比较好。搭建如下:
content节点不添加任何组...
抽空做了一个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); } } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。