当前位置: 移动技术网 > IT编程>开发语言>c# > UGUI实现ScrollView无限滚动效果

UGUI实现ScrollView无限滚动效果

2019年07月18日  | 移动技术网IT编程  | 我要评论

抽空做了一个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);
    }
  }
 
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网