简易版
private void SetItemList(List items)
{
foreach(var item in items)
{
var cell = Instantiate(ResourcesLoader.Load("UI/prefab/UIEquip")) as GameObject;
cell.transform.SetParent(this.itemsBg.transform);
UIEquip script = cell.GetComponent();
script.InitSetCell();
}
}
优化版--协程异步加载
当列表数量多卡顿时
StartCoroutine(SetItemList(items)); //协程
private IEnumerator SetItemList(List items)
{
foreach(var item in items)
{
var cell = Instantiate(ResourcesLoader.Load("UI/prefab/UIEquip")) as GameObject;
cell.transform.SetParent(this.itemsBg.transform);
UIEquip script = cell.GetComponent();
script.InitSetCell();
yield return null; //每执行一次循环就先返回主流程,隔一帧再执行下一次循环
}
}
当然,如果主流程多次调用了这个协程,会因为列表项添加到父节点时机问题导致列表项重复加载,则需要把yield reture 放到for循环外面
StartCoroutine(SetItemList(items)); //协程
private IEnumerator SetItemList(List items)
{
yield return null; //执行到这里时先返回主流程,下一帧再回来执行循环
ClearLayouGroup(); //先清空父节点,再循环添加列表项,防重复添加
foreach(var item in items)
{
var cell = Instantiate(ResourcesLoader.Load("UI/prefab/UIItem")) as GameObject;
cell.transform.SetParent(this.itemsParent.transform);
UIEquip script = cell.GetComponent();
script.InitSetCell(); //初始化设置每个列表项实例的业务逻辑内容
}
}
private void ClearLayouGroup() //清空列表项父节点下的所有实例
{
var exNodeCloneList = layoutGroup.GetComponentsInChildren();
if (exNodeCloneList == null || exNodeCloneList.Length==0)
{
return;
}
foreach (var node in exNodeCloneList)
{
Destroy(node.gameObject);
}
}
优化版--渲染与数据分离
数据变动事件驱动渲染刷新
当列表项非常多导致卡顿,而协程也难以满足复杂业务需求时,可以考虑通过MVC分离数据和渲染的变动;
Model
public class ItemCell : object
{
public GameObject item; //单个列表项
public int _index; //列表项索引
}
组件:
public class ScrollRectList : MonoBehaviour/*, IDragHandler*/
{
private List hideItems = new List();
Action hideitemobject;
Action updateItem;
// 滚动列表初始化
public void Init(int DataCount)
{
this.DestroyAllItems();
this._content.anchoredPosition = Vector2.zero;
this._index = -1;
this._itemList = new List();
this.DataCount = DataCount;
this.OnValueChange(Vector2.zero);
if (this.initafter != null)
{
this.initafter();
}
}
public void OnValueChange(Vector2 pos)
{
pos = isMirror? new Vector2(pos.x, pos.y*-1): pos ;
if (this._itemList == null)
{
return;
}
int index = this.GetPosIndex();
if (this._index != index && index > -1)
{
this._index = index;
//计算不显示对象
for (int i = 0; i < this._itemList.Count; i++)
{
ItemCell item = this._itemList[i];
int itemIndex = this.getItemIndex(item);
if (itemIndex < index * this.maxPerLine || (itemIndex >= (index + this.viewCount) * this.maxPerLine))
{
this.hideItems.Add(item);
if (this.hideitemobject != null)
{
this.hideitemobject(item);
}
}
}
foreach (ItemCell o in this.hideItems)
{
this._itemList.Remove(o);
}
//计算显示对象
for (int i = this._index * this.maxPerLine; i < (this._index + this.viewCount) * this.maxPerLine; i++)
{
if (i < 0)
{
continue;
}
if (i > this._dataCount - 1)
{
continue;
}
if (this._itemList.Find(delegate (ItemCell item) { return getItemIndex(item) == i; }) == null)
{
if (this.hideItems.Count > 0)
{
ItemCell o = this.hideItems[0];
o.item.transform.gameObject.SetActive(true);
this.hideItems.Remove(o);
this._itemList.Add(o);
this.updateItem(o, i);
this.setItemIndex(o, i);
}
else
{
this.CreateItem(i);
}
}
}
if (this.hideItems.Count > 0)
{
for (int i = 0; i < this.hideItems.Count; i++)
{
ItemCell item_ = this.hideItems[i];
item_.item.transform.gameObject.SetActive(false);
}
}
}
else
{
//_content.position = Vector3.zero;
}
}
private void CreateItem(int index)
{
GameObject o = this.createitemobject();
if (o != null && this._content != null)
{
o.transform.SetParent(this._content.transform);
o.GetComponent().pivot = isMirror?new Vector2(0f, 0f):new Vector2(0f, 1f);
o.GetComponent().sizeDelta = new Vector2(this.cellWidth, this.cellHeight);
o.transform.localScale = (isMirror? new Vector3(this.scale.x, this.scale.y*-1, this.scale.z): this.scale);
ItemCell itemcell = new ItemCell();
itemcell._index = index;
itemcell.item = o;
this.setItemIndex(itemcell, index);
this.updateItem(itemcell, index);
this._itemList.Add(itemcell);
}
}
}
调用:
public class UIHeroPackage : Monobehavier
{
GameObject sniperCell = null;
this.Grid.createitemobject = delegate ()
{
GameObject cell = UICommon.Instance.LoadUIItems();
sniperCell = cell;
return cell;
};
this.Grid.deleteitemobject = delegate (ItemCell cell)
{
UICommon.Instance.DeleteUIItems(cell.item);
};
this.Grid.updateItem = delegate (ItemCell cell, int index)
{
cell.item.SetActive(true);
index *= 2;
int tid = this.HeroDict[this.currentPage][index];
UpdateUIItems();
if (isInit)
{
this.Grid.Init((this.ItemsDict[this.currentPage].Count + 1) / 2);
}
}
另外参考:
基于Unity UGUI实现的RecycleList循环列表UI容器 - HelloGalaxy - 博客园
基于Unity UGUI实现的RecycleList循环列表UI容器_weixin_30326741的博客-CSDN博客