NGUI ScrollView实现循环优化
List<DataUnit> dataList;
当dataList的数据很多时,如果直接把所有的item挂在UIGrid下面,效率显然是十分低下的。这时用UIWrapContent就可以实现列表的循环复用(通过循环几个item实例表现大量的数据)
在NGUI中高效优化UIScrollView之UIWrapContent的简介以及使用
UIWrapContent的大致用法:
a)UIWrapContent.onInitializeItem是列表循环复用时重设表项数据的委托:
1 class xxx: MonoBehaviour 2 { 3 public UIWrapContent _wrapScript; 4 void Awake() 5 { 6 //绑定方法 7 _wrapScript.onInitializeItem = OnUpdateItem; 8 } 9 void OnUpdateItem(GameObject go, int index, int realIndex) 10 { 11 tb.SetNumber(realIndex.ToString()); 12 } 13 }
b)当列表为横向时 minIndex=0,maxIndex= dataList.Count-1;当列表为纵向时 minIndex = -dataList.Count+1,maxIndex =0;
c)用代码addChild item后需要手动调用一次SortBasedOnScrollMovement()刷新界面
d)当dataList.Count==1时 minIndex==maxIndex==0 。按照UIWrapContent的逻辑,这种情况实现的是无限循环列表,不符合当前的需求,所以要对UIWrapContent.WrapContent进行改写:
/// <summary> /// Wrap all content, repositioning all children as needed. /// </summary> public void WrapContent () { float extents = itemSize * mChildren.Count * 0.5f; Vector3[] corners = mPanel.worldCorners; for (int i = 0; i < 4; ++i) { Vector3 v = corners[i]; v = mTrans.InverseTransformPoint(v); corners[i] = v; } Vector3 center = Vector3.Lerp(corners[0], corners[2], 0.5f); bool allWithinRange = true; float ext2 = extents * 2f; if (mHorizontal) { float min = corners[0].x - itemSize; float max = corners[2].x + itemSize; for (int i = 0, imax = mChildren.Count; i < imax; ++i) { Transform t = mChildren[i]; float distance = t.localPosition.x - center.x; if (distance < -extents) { Vector3 pos = t.localPosition; pos.x += ext2; distance = pos.x - center.x; int realIndex = Mathf.RoundToInt(pos.x / itemSize); if ((minIndex <= realIndex && realIndex <= maxIndex)) { t.localPosition = pos; UpdateItem(t, i); } else allWithinRange = false; } else if (distance > extents) { Vector3 pos = t.localPosition; pos.x -= ext2; distance = pos.x - center.x; int realIndex = Mathf.RoundToInt(pos.x / itemSize); if ((minIndex <= realIndex && realIndex <= maxIndex)) //if (minIndex == maxIndex || (minIndex <= realIndex && realIndex <= maxIndex)) { t.localPosition = pos; UpdateItem(t, i); } else allWithinRange = false; } else if (mFirstTime) UpdateItem(t, i); if (cullContent) { distance += mPanel.clipOffset.x - mTrans.localPosition.x; if (!UICamera.IsPressed(t.gameObject)) NGUITools.SetActive(t.gameObject, (distance > min && distance < max), false); } } } else { float min = corners[0].y - itemSize; float max = corners[2].y + itemSize; for (int i = 0, imax = mChildren.Count; i < imax; ++i) { Transform t = mChildren[i]; float distance = t.localPosition.y - center.y; if (distance < -extents) { Vector3 pos = t.localPosition; pos.y += ext2; distance = pos.y - center.y; int realIndex = Mathf.RoundToInt(pos.y / itemSize); if ((minIndex <= realIndex && realIndex <= maxIndex)) // if (minIndex == maxIndex || (minIndex <= realIndex && realIndex <= maxIndex)) { t.localPosition = pos; UpdateItem(t, i); } else allWithinRange = false; } else if (distance > extents) { Vector3 pos = t.localPosition; pos.y -= ext2; distance = pos.y - center.y; int realIndex = Mathf.RoundToInt(pos.y / itemSize); if ((minIndex <= realIndex && realIndex <= maxIndex)) // if (minIndex == maxIndex || (minIndex <= realIndex && realIndex <= maxIndex)) { t.localPosition = pos; UpdateItem(t, i); } else allWithinRange = false; } else if (mFirstTime) UpdateItem(t, i); if (cullContent) { distance += mPanel.clipOffset.y - mTrans.localPosition.y; if (!UICamera.IsPressed(t.gameObject)) NGUITools.SetActive(t.gameObject, (distance > min && distance < max), false); } } } mScroll.restrictWithinPanel = !allWithinRange; }