程序员人生 网站导航

NGUI UIScrollView - 大量item子项的性能优化

栏目:互联网时间:2014-11-15 06:17:02

1、当UIScrollView的下面的包括的子项太多(2310个之上)时,它的转动就会变的很卡。

对些网上也有很多的优化它的相干,下面是我的1个优化:

1、将在超越裁剪框的1个item的距离的item,从scrollview中烧毁掉 。当它将要出现在裁剪框中时,再将它构造出来。-- 大家好你都是这么做的。

2、为避免频繁的构造、烧毁,致使频繁的分配内存和产生大量的内存垃圾内,致使的性能问题,我增加了1个对象池来管理item的构造与移除工作。

3、scrollvew中的元素在1般情况下,其中的item是要求等距的,如果它的大小不1样,它们的距离就会良莠不齐。而这个问题在我的优化中是不存在的。

4、最主要是代码量少、使用简单、扩大方便。


2、话不多说,上代码:

1、主类:Lzh_LoopScrollView.cs

/* * 描术: * * 作者:AnYuanLzh * 公司:lexun * 时间:2014-xx-xx */ using UnityEngine; using System.Collections.Generic; /// <summary> /// 这个类主要做了1件事,就是优化了,NGUI UIScrollView 在数据量很多都时候, /// 创建过量都GameObject对象,造成资源浪费. /// </summary> public class Lzh_LoopScrollView : MonoBehaviour { public enum ArrangeDirection { Left_to_Right, Right_to_Left, Up_to_Down, Down_to_Up, } /// <summary> /// items的排列方式 /// </summary> public ArrangeDirection arrangeDirection = ArrangeDirection.Up_to_Down; /// <summary> /// 列表单项模板 /// </summary> public GameObject itemPrefab; /// <summary> /// The items list. /// </summary> public List<Lzh_LoopItemObject> itemsList; /// <summary> /// The datas list. /// </summary> public List<Lzh_LoopItemData> datasList; /// <summary> /// 列表脚本 /// </summary> public UIScrollView scrollView; public GameObject itemParent; /// <summary> /// itemsList的第1个元素 /// </summary> Lzh_LoopItemObject firstItem; /// <summary> /// itemsList的最后1个元素 /// </summary> Lzh_LoopItemObject lastItem; public delegate void DelegateHandler(Lzh_LoopItemObject item, Lzh_LoopItemData data); /// <summary> /// 响应 /// </summary> public DelegateHandler OnItemInit; /// <summary> /// 第1item的起始位置 /// </summary> public Vector3 itemStartPos = Vector3.zero; /// <summary> /// 菜单项间隙 /// </summary> public float gapDis = 0f; // 对象池 // 再次优化,频繁的创建与烧毁 Queue<Lzh_LoopItemObject> itemLoop = new Queue<Lzh_LoopItemObject>(); void Awake() { if(itemPrefab==null || scrollView==null || itemParent==null) { Debug.LogError("Lzh_LoopScrollView.Awake() 有属性没有在inspector中赋值"); } // 设置scrollview的movement if(arrangeDirection == ArrangeDirection.Up_to_Down || arrangeDirection == ArrangeDirection.Down_to_Up) { scrollView.movement = UIScrollView.Movement.Vertical; } else { scrollView.movement = UIScrollView.Movement.Horizontal; } } // Update is called once per frame void Update () { //if(scrollView.isDragging) { Validate(); } } /// <summary> /// 检验items的两端是不是要补上或删除 /// </summary> void Validate() { if( datasList==null || datasList.Count==0) { return; } // 如果itemsList还不存在 if(itemsList==null || itemsList.Count==0) { itemsList = new List<Lzh_LoopItemObject>(); Lzh_LoopItemObject item = GetItemFromLoop(); InitItem(item, 0, datasList[0]); firstItem = lastItem = item; itemsList.Add(item); //Validate(); } // bool all_invisible = true; foreach(Lzh_LoopItemObject item in itemsList) { if(item.widget.isVisible==true) { all_invisible=false; } } if (all_invisible == true) return; // 先判断前端是不是要增减 if(firstItem.widget.isVisible) { // 判断要不要在它的前面补充1个item if(firstItem.dataIndex>0) { Lzh_LoopItemObject item = GetItemFromLoop(); // 初化:数据索引、大小、位置、显示 int index = firstItem.dataIndex⑴; //InitItem(item, index, datasList[index]); AddToFront(firstItem, item, index, datasList[index]); firstItem = item; itemsList.Insert(0,item); //Validate(); } } else { // 判断要不要将它移除 // 条件:本身是不可见的;且它后1个item也是不可见的(或被被裁剪过半的). // 这有个隐含条件是itemsList.Count>=2. if(itemsList.Count>=2 && itemsList[0].widget.isVisible==false && itemsList[1].widget.isVisible==false) { itemsList.Remove(firstItem); PutItemToLoop(firstItem); firstItem = itemsList[0]; //Validate(); } } // 再判断后端是不是要增减 if(lastItem.widget.isVisible) { // 判断要不要在它的后面补充1个item if(lastItem.dataIndex < datasList.Count⑴) { Lzh_LoopItemObject item = GetItemFromLoop(); // 初化:数据索引、大小、位置、显示 int index = lastItem.dataIndex+1; AddToBack(lastItem, item, index, datasList[index]); lastItem = item; itemsList.Add(item); //Validate(); } } else { // 判断要不要将它移除 // 条件:本身是不可见的;且它前1个item也是不可见的(或被被裁剪过半的). // 这有个隐含条件是itemsList.Count>=2. if(itemsList.Count>=2 && itemsList[itemsList.Count⑴].widget.isVisible==false && itemsList[itemsList.Count⑵].widget.isVisible==false) { itemsList.Remove(lastItem); PutItemToLoop(lastItem); lastItem = itemsList[itemsList.Count⑴]; //Validate(); } } } /// <summary> /// Init the specified datas. /// </summary> /// <param name="datas">Datas.</param> public void Init(List<Lzh_LoopItemData> datas, DelegateHandler onItemInitCallback) { datasList = datas; this.OnItemInit = onItemInitCallback; Validate(); } /// <summary> /// 构造1个 item 对象 /// </summary> /// <returns>The item.</returns> Lzh_LoopItemObject CreateItem() { GameObject go = NGUITools.AddChild(itemParent,itemPrefab); UIWidget widget = go.GetComponent<UIWidget>(); Lzh_LoopItemObject item = new Lzh_LoopItemObject(); item.widget = widget; go.SetActive(true); return item; } /// <summary> /// 用数据列表来初始化scrollview /// </summary> /// <param name="item">Item.</param> /// <param name="indexData">Index data.</param> /// <param name="data">Data.</param> void InitItem(Lzh_LoopItemObject item, int dataIndex, Lzh_LoopItemData data) { item.dataIndex = dataIndex; if(OnItemInit!=null) { OnItemInit(item, data); } item.widget.transform.localPosition = itemStartPos; } /// <summary> /// 在itemsList前面补上1个item /// </summary> void AddToFront(Lzh_LoopItemObject priorItem, Lzh_LoopItemObject newItem, int newIndex, Lzh_LoopItemData newData) { InitItem (newItem, newIndex, newData); // 计算新item的位置 if(scrollView.movement == UIScrollView.Movement.Vertical) { float offsetY = priorItem.widget.height*0.5f + gapDis + newItem.widget.height*0.5f; if(arrangeDirection == ArrangeDirection.Down_to_Up) offsetY *=⑴f; newItem.widget.transform.localPosition = priorItem.widget.cachedTransform.localPosition + new Vector3(0f, offsetY, 0f); } else { float offsetX = priorItem.widget.width*0.5f + gapDis + newItem.widget.width*0.5f; if(arrangeDirection == ArrangeDirection.Right_to_Left) offsetX *=⑴f; newItem.widget.transform.localPosition = priorItem.widget.cachedTransform.localPosition - new Vector3(offsetX, 0f, 0f); } } /// <summary> /// 在itemsList后面补上1个item /// </summary> void AddToBack(Lzh_LoopItemObject backItem, Lzh_LoopItemObject newItem, int newIndex, Lzh_LoopItemData newData) { InitItem (newItem, newIndex, newData); // 计算新item的位置 if(scrollView.movement == UIScrollView.Movement.Vertical) { float offsetY = backItem.widget.height*0.5f + gapDis + newItem.widget.height*0.5f; if(arrangeDirection == ArrangeDirection.Down_to_Up) offsetY *=⑴f; newItem.widget.transform.localPosition = backItem.widget.cachedTransform.localPosition - new Vector3(0f, offsetY, 0f); } else { float offsetX = backItem.widget.width*0.5f + gapDis + newItem.widget.width*0.5f; if(arrangeDirection == ArrangeDirection.Right_to_Left) offsetX *=⑴f; newItem.widget.transform.localPosition = backItem.widget.cachedTransform.localPosition + new Vector3(offsetX, 0f, 0f); } } #region 对象池性能相干 /// <summary> /// 从对象池中取行1个item /// </summary> /// <returns>The item from loop.</returns> Lzh_LoopItemObject GetItemFromLoop() { Lzh_LoopItemObject item; if(itemLoop.Count<=0) { item = CreateItem(); } else { item = itemLoop.Dequeue(); } item.widget.gameObject.SetActive(true); return item; } /// <summary> /// 将要移除的item放入对象池中 /// --这个里我保证这个对象池中存在的对象不超过3个 /// </summary> /// <param name="item">Item.</param> void PutItemToLoop(Lzh_LoopItemObject item) { if(itemLoop.Count>=3) { Destroy(item.widget.gameObject); return; } item.dataIndex = ⑴; item.widget.gameObject.SetActive(false); itemLoop.Enqueue(item); } #endregion }



2、item对像的封装类:Lzh_LoopItemObject,不要求具体的item类来继承它,但我们要示具体的item对像1定要包括UIWidget组件。

/* * 描术: * * 作者:AnYuanLzh * 公司:lexun * 时间:2014-xx-xx */ using UnityEngine; using System.Collections; /// <summary> /// item对像的封装类Lzh_LoopItemObject,不要求具体的item类来继承它。 /// 但我们要示具体的item对像1定要包括UIWidget组件。 /// </summary> [System.Serializable] public class Lzh_LoopItemObject { /// <summary> /// The widget. /// </summary> public UIWidget widget; /// <summary> /// 本item,在实际全部scrollview中的索引位置, /// 即对就数据,在数据列表中的索引 /// </summary> public int dataIndex= ⑴; }



3、与item对关联的数据类:Lzh_LoopItemData,具体的item的数据类1定继承它

/* * 描术: * * 作者:AnYuanLzh * 公司:lexun * 时间:2014-xx-xx */ using UnityEngine; using System.Collections; /// <summary> /// 与item对关联的数据类,具体的item的数据类1定继承它 /// </summary> public class Lzh_LoopItemData { // *** }

4、上面3个是主要的类,注释也比较详细。

4、demo工程

具体的使用请下载我的demo工程

1、demo的运行效果图:

              

2、demo下载:这个包中1份工程码和1个build好的可运行的exe。

   (注:其代码工程中缺少NGUI插件,而要你们自行加上,这个demo我用的是ngui3.7.4。我觉得相近的其它版ngui也是行的)


------分隔线----------------------------
------分隔线----------------------------

最新技术推荐