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; }