当前位置:   article > 正文

unity NGUI 中ScrollView大量物体的优化方式:重用item_unity中击scrollview里面的item

unity中击scrollview里面的item

不管是游戏还是软件,列表(ScrollView)都是算是最常用的控件之一。列表中的内容少的几个,而多的时候几千上万个,这时候如果我们不对列表进行优化,直接加载所有物体肯定是不现实的。当然这个问题的优化策略网上也不少,最多的就是重用item,大概看了一些,不是做的非常复杂就是说的含糊不清,所以这里自己动手写了个demo,简单易懂,代码量很少,一共100多行代码,这里分享出来。

基本思想就是当列表向上移动时,我们就把超出屏幕上部的item移动到列表末尾位置并重置数据。当列表向下移动时,就把超出屏幕下部的item移动到列表开头。


首先创建Scroll View ,Grid并把他们设置为竖向的,调整好尺寸。

在创Grid下建一个我们想要的item,不要忘记添加BosCollider和UIDragScrollView,BosCollider要勾选IsTrigger。并制作成预制体。

制作完后运行场景,一切顺利的话我们可以看到一个item,并且可以在ScrollView范围内拖拽.


现在开始编写脚本:

创建一个数据类ScrollViewItemData:

  1. public class ScrollViewItemData {
  2. public int index;
  3. public string name;
  4. public ScrollViewItemData(int index,string name){
  5. this.index = index;
  6. this.name = name;
  7. }
  8. }

这个类应该是列表中每个item的原始数据。这里我们只简单的定一个2个数据,一个索引,一个name。

索引用来记录当前数据的顺序,name用来作为需要显示的内容。


然后创建item的脚本ScrollViewItem:

  1. public class ScrollViewItem : MonoBehaviour {
  2. UILabel label;
  3. public ScrollViewItemData data;
  4. // Use this for initialization
  5. void Awake () {
  6. label = transform.Find("Label").GetComponent<UILabel> ();
  7. }
  8. public void SetData(ScrollViewItemData data){
  9. this.data = data;
  10. label.text = data.name ;
  11. }
  12. // Update is called once per frame
  13. void Update () {
  14. }
  15. }
这里我们声明了一个ScrollViewItemData类的引用,用来记录当前item显示的是哪一条数据。我在预制体中增加的一个UILabel用来显示当前数据的name。我们需要把这个脚本放到之前创建的item的预制体上。

接下来是核心的列表控制器ScrollViewManager,先上完整代码:

  1. public class ScrollViewManager : MonoBehaviour {
  2. List<ScrollViewItem> itemList = new List<ScrollViewItem>();
  3. List<ScrollViewItemData> itemDataList = new List<ScrollViewItemData> ();
  4. UIScrollView sv;
  5. UIGrid grid;
  6. //记录scrollviet上一次的位置,用于判断scrollview的移动方向
  7. float svLastPos = 0;
  8. //最大y坐标
  9. float maxHeight = 0;
  10. //最小y坐标
  11. float minHeight = 0;
  12. // Use this for initialization
  13. void Start () {
  14. //初始化测试数据
  15. for (int i = 0; i < 20; i++) {
  16. itemDataList.Add (new ScrollViewItemData (i,"第" + i + "个元素"));
  17. }
  18. sv = transform.GetComponent<UIScrollView> ();
  19. grid = transform.Find ("Grid").GetComponent<UIGrid>();
  20. Vector2 viewsize = transform.GetComponent<UIPanel> ().GetViewSize ();
  21. int count = (int)(viewsize.y / grid.cellHeight + 2);
  22. Debug.Log (count);
  23. for (int i = 0; i < count ; i++) {
  24. if (itemDataList.Count <= i)
  25. break;
  26. GameObject o = Resources.Load("Prefabs/ScrollViewItem") as GameObject;
  27. GameObject obj = NGUITools.AddChild(grid.gameObject, o);
  28. ScrollViewItem item = obj.GetComponent<ScrollViewItem>();
  29. itemList.Add (item);
  30. item.SetData (itemDataList[i]);
  31. }
  32. grid.repositionNow = true;
  33. grid.Reposition();
  34. svLastPos = grid.transform.localPosition.y;
  35. maxHeight = viewsize.y / 2 + grid.cellHeight / 2;
  36. minHeight = -maxHeight;
  37. }
  38. // Update is called once per frame
  39. void Update () {
  40. float moveDis = sv.transform.localPosition.y - svLastPos;
  41. if (Mathf.Abs(moveDis) > 0.05) {
  42. bool isup = moveDis > 0;
  43. if (isup) {
  44. while (itemList [0].transform.localPosition.y + sv.transform.localPosition.y > maxHeight &&
  45. itemList [itemList.Count - 1].data.index < itemDataList.Count - 1) {
  46. ScrollViewItem item = itemList [0];
  47. item.SetData (itemDataList [itemList [itemList.Count - 1].data.index + 1]);
  48. itemList.Add (item);
  49. itemList.RemoveAt (0);
  50. item.transform.localPosition = itemList[itemList.Count - 2].transform.localPosition -
  51. new Vector3 (0,grid.cellHeight,0);
  52. }
  53. } else {
  54. while (itemList [itemList.Count - 1].transform.localPosition.y + sv.transform.localPosition.y < minHeight &&
  55. itemList [0].data.index > 0) {
  56. ScrollViewItem item = itemList [itemList.Count - 1];
  57. item.SetData (itemDataList [itemList [0].data.index - 1]);
  58. itemList.Insert (0, item);
  59. itemList.RemoveAt (itemList.Count - 1);
  60. item.transform.localPosition = itemList[1].transform.localPosition +
  61. new Vector3 (0,grid.cellHeight,0);
  62. }
  63. }
  64. svLastPos = sv.transform.localPosition.y;
  65. }
  66. }
  67. }


首先我们定义了两个列表用来保存所有的item物体以及列表中的全部数据.

由于没有在UIScrollView的API中找到获取当前移动方向的接口,所以这里只能定义一个变量svLastPos自己记录一下位置,进行判断。

然后定义了2个变量用于判断item移出屏幕的最大和最小距离。

先看Start函数

1.先初始化了20个测试数据。

2.然后计算需要生成多少个item对象,这里我们用整个ScrollView的高度除以每个item的高度得到屏幕中一共能显示多少个item,然后加上2个以避免item不足的情况出现。

3.然后创建item并初始化数据。

4.最后计算屏幕的最大高度和最小高度。


然后是Update方法:

1.判断列表是否移动,用现在的位置-之前记录的位置的绝对值进行判断,如果移动了,开始我们重置item的逻辑。

2.判断移动方向,如果向上则判断item列表中第0个元素是否超出坐标范围,如果向下移动则判断最后一个元素。

这里为了避免移动过快出现bug,我们使用while将所有超出范围的item一起进行处理。

还要判断数据列表中是否超出范围如果超出范围说明没有数据,不需要继续重置item的位置了。

4.如果需要移动item,首先将item中的数据设置为目标数据,这里直接取item列表最后一个元素获取到数据的index并且+1就是目标数据,然后将当前item添加到列表末尾同时删除列表第一个元素,最后设置item的坐标。向上移动和向下移动的逻辑正好相反,这里不再复述。

来看下最后的效果:






声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号