UGUI实现ScrollView无限滚动效果

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

}

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

(0)

相关推荐

  • Unity实现游戏卡牌滚动效果

    最近项目中的活动面板要做来回滚动卡牌预览效果,感觉自己来写的话,也能写,但是可能会比较耗时,看到Github上有开源的项目,于是就借用了,Github的资源地址,感谢作者的分享. 本篇博客旨在告诉大家如何利用这个插件. 插件的核心在于工程中的6个脚本,以下是六个脚本的源码: DragEnhanceView.cs using UnityEngine; using System.Collections; using UnityEngine.UI; using UnityEngine.EventSys

  • Unity实现轮盘方式的按钮滚动效果

    近期在项目中,策划给出了一个需求就是,让按钮按照一个轮盘的轨迹进行滑动的效果,经过一番测试,实现了初步的效果. 我这里区分了横向滑动和纵向滑动,这里以纵向滑动为例子进行示范,实现按钮的滑动效果. 首先就是先进行位置初始化: /// <summary> ///从大到小排序,Y轴 /// </summary> private Comparison<CircleScrollRectItemBase> ComparisionY = delegate (CircleScrollR

  • Unity实现3D循环滚动效果

    本文实例为大家分享了Unity实现3D循环滚动效果展示的具体代码,供大家参考,具体内容如下 然后通过SetDepthAndPosition这个方法,实现图片的空间空间展开 Z轴和Y轴,系数是一样的 经过上面设置,空间就摆开了 using UnityEngine; using System.Collections; using System.Collections.Generic; public class SelectRole : MonoBehaviour { public GameObjec

  • UGUI实现ScrollView无限滚动效果

    抽空做了一个UGUI的无限滚动的效果.只做了一半(向下无限滚动).网上也看了很多教程,感觉还是按照自己的思路来写可能比较好.搭建如下: content节点不添加任何组件.布局组件默认是会重新排版子节点的,所以如果子节点的位置变化,会重新排版,不能达到效果.Size Fitter组件也不加,自己写代码调整Size大小(不调整大小,无法滑动). 最主要的实现过程就是用Queue来搬运Cell.在向下滚动的过程中(鼠标上滑),顶部滑出View Port的Cell被搬运到底部续上.这点类似于Queue的

  • 使用Swift实现iOScollectionView广告无限滚动效果(DEMO)

    今天公司里的实习生跑过来问我一般App上广告的无限滚动是怎么实现的,刚好很久没写博客了,就决定写下了,尽量帮助那些处于刚学iOS的程序猿. 做一个小demo,大概实现效果如下图所示: 基本实现思路: 1. 在你需要放置无限滚动展示数据的地方把他的数据,在原本的基础上把你要展示的数据扩大三倍.(当然扩大两倍也是可以的,三倍的话,比较好演示) // MARK: - 设置数据源 func collectionView(_ collectionView: UICollectionView, number

  • 使用vue-infinite-scroll实现无限滚动效果

    vue-infinite-scroll插件可以无限滚动实现加载更多,其作用是是当滚动条滚动到距离底部的指定高度时触发某个方法. https://github.com/ElemeFE/vue-infinite-scroll/ https://www.npmjs.com/package/vue-infinite-scroll npm i vue-infinite-scroll --save main.js使用 import vueiInfinite from 'vue-infinite-scroll

  • Android使用ScrollView实现滚动效果

    本文实例为大家分享了ScrollView实现滚动效果的具体代码,供大家参考,具体内容如下 如果长文本的内容超过一屏幕 则只能显示一屏幕的内容 设置ScrollView 通过滚动浏览下面的内容 若将标签更改为<HorizontalScrollView></HorizontalScrollView>则为水平滚动效果 xml文件: <?xml version="1.0" encoding="utf-8"?> <android.su

  • iOS利用UIScrollView实现无限滚动效果

    前言 众所周知UIScrollView 的无限滚动主要应用在图片轮播器.欢迎界面等场景.它的原理是在要显示的图片前后各加一张图片即在第一张图片之前放最后一张图片,在最后一张图片之后放第一张图片,然后在滚动到边缘的时候,巧妙的过渡一下就可以"瞒天过海","以假乱真"的造成无限滚动的假象.网络上有很多只用三张或两张图片实现的方法,效率比这个方法高,但实现起来稍微麻烦一点,有兴趣的可以去深入研究. 实现步骤 1.根据需求准备几张图片,在网上找了5张图片,分别命名为 img

  • IOS中无限滚动Scrollview效果

    本文实例讲了IOS无限滚动效果,分享给大家供大家参考,具体内容如下 滑动到当前位置时候才去请求,本地有内容则直接显示(以来SDWebImage,UIView+Ext) HZScrollView.h #import <UIKit/UIKit.h> typedef void(^HZReturnBlock)(NSInteger index,CGFloat offset); typedef NS_ENUM(NSUInteger, HZScrollViewPageControllPosition) {

  • Unity ScrollView实现无限循环效果

    本文实例为大家分享了Unity ScrollView实现无限循环效果的具体代码,供大家参考,具体内容如下 在Unity引擎中ScrollView组件是一个使用率比较高的组件,该组件能上下或者左右拖动的UI列表,背包.展示多个按钮等情况的时候会用到,在做排行榜类似界面时,item非常多,可能有几百个,一次创建这么多GameObject是非常卡的.为此,使用只创建可视区一共显示的个数,加上后置准备个数. 由于ScrollView有两种滚动方式,水平滚动或者垂直滚动,所以我创建了ScrollBase基

  • Unity ScrollView实现无限滑动效果

    本文实例为大家分享了Unity ScrollView实现无限滑动效果的具体代码,供大家参考,具体内容如下 一.效果演示 二.前言 当邮件中有1000封邮件,商店列表中有1000个物体,如果直接实例化1000条数据显示则会大大增加DrawCall,而大量不可见的数据被Mask组件排除在可视范围之外,但他们依然存在,这时就需要考虑通过一个无限滑动的ScrollView来优化渲染性能 三.实现思路 通过头下标和尾下标记录当前实例化数据的最大最小索引,之后用Content的锚点位置与当头下标的锚点位置进

  • Android实现两个ScrollView互相联动的同步滚动效果代码

    本文实例讲述了Android实现两个ScrollView互相联动的同步滚动效果代码.分享给大家供大家参考,具体如下: 最近在做一个项目,用到了两个ScrollView互相联动的效果,简单来说联动效果意思就是滑动其中的一个ScrollView另一个ScrollView也一同跟着滑动,要做到一起同步滑动.感觉在以后的项目开发中大家可能也会用到,绝对做个Demo分享出来,供大家一起学习,以便大家以后好用,觉的不错,有用的可以先收藏起来哦! 其实对于ScrollView,Android官方并没有提供相关

  • jQuery实现无限往下滚动效果代码

    本文实例讲述了jQuery实现无限往下滚动效果的方法.分享给大家供大家参考,具体如下: 这是仿照腾讯的微薄上的一个效果.滚动条可以无限的网下滚动并且无刷不断从数据库中获取新的数据. <style type="text/css"> body{ font-family: "Trebuchet MS",verdana,arial;} #loading{ display:none; font-weight:bold;color:#FF0000;} p { pad

随机推荐