Unity3D UIGrid 排序、动态加载与销毁

发表于2015-07-31
评论2 3.1k浏览
做 UIGrid 的动态加载是做游戏的装备列表时用到的,装备信息都是从后台发过来的,具体加载的代码如下:
for(int i = 0 ; i < itemData.Item_List.Count; i++)
{
     Data dataMgr = (Data)itemData.Item_List;
     setGridDataIconImage(dataMgr);
 
private void setGridDataIconImage(Data Obj){
 
     grid = GameObject.Find("UIGrid").GetComponent<UIGrid>();
     atlas = Resources.Load("Equip/Equip_Atlas", typeof(UIAtlas)) as UIAtlas;
     parent = GameObject.Find("UIGrid");
 
     GameObject o = Resources.Load("EquipItem_prefab")as GameObject;
     Item item = o.GetComponent<Item>();
 
     if (null == equipStoreObj) {
     item.isRemoveItem = true;
     }
     else{
     item.s_item_id = equipStoreObj.store_itemID;
     item.s_info1 = equipStoreObj.store_info1;
     item.s_info2 = equipStoreObj.store_info2;
     m_MainModel.getAtlasNameAndSpriteImageNameFromEquipID(equipStoreObj.info1,ref item.atlasName,ref      item.spriteImageName);
     }
 
     item.Equip.MakePixelPerfect();
 
     NGUITools.AddChild(parent, o);
     //列表添加后用于刷新listView
     grid.repositionNow = true;
     grid.maxPerLine = 5;
     //重设uigrid
     grid.Reposition();
}
最大的问题出在下面,就是当我需要更新 UIGrid的时候 我需要销毁旧的,加入新的 List 内容,现在正确的写法如下
public void sortLv()
    {
        // 销毁现有元素
        while (grid.transform.childCount > 0)
        {
            DestroyImmediate(grid.transform.GetChild(0).gameObject);
        }
        // 加入新元素
        for (int i = 0; i < itemData.Item_Equip_Store_List.Count; i++)
        {
            EquipDataManager equipTable = itemData.Item_Equip_Store_List;
            setGridDataIconImage(equipTable);
        }
    }
开始我使用了 for 循环来完成删除
for(int i = 0; i < grid.transform.childCount; i++)
{
     Destroy(grid.transform.GetChild(0).gameObject);
}


这里有两个问题,首先每一次销毁 grid 元素的 List 会自动进行空白缩减,所以 grid.transform.childCount 的值是一直在变的,元素的销毁就会出问题,而上面正确的方式就是因为 由于每一次销毁都自动缩减所以其实 while中的值一直在递减,所以看似是一个死循环,其实这样写才是正确的。

Destroy 和 DestroyImmediate 的区别

API 手册中这样说

DestroyImmediate
Destroys the object obj immediately. It is strongly recommended to use Destroy instead.
立即销毁物体obj,强烈建议使用Destroy代替。
This function should only be used when writing editor code since the delayed destruction will never be invoked in edit mode. In game code it is recommended to use Object.Destroy instead. Destroy is always delayed (but executed within the same frame) Use this function with care since it can destroy assets permanently!
该函数只在写编辑器代码时使用,因为延时的销毁永远不会在编辑模式下调用。在游戏代码推荐使用Object.Destroy代替。销毁总是延迟的(但在同一帧内执行),小心使用该函数,因为它能永久销毁资源。

Destory
The object obj will be destroyed now or if a time is specified t seconds from now. If obj is a Component it will remove the component from the GameObject and destroy it. If obj is a GameObject it will destroy the GameObject, all its components and all transform children of the GameObject. Actual object destruction is always delayed until after the current Update loop, but will always be done before rendering. 

物体obj现在被销毁或在指定了t时间过后销毁。如果obj是组件,它将从GameObject销毁组件component。如果obj是GameObject它将销毁GameObject全部它的组件和GameObject全部transform子物体。实际物体的销毁总是延迟到当前更新循环后,但总是渲染之前完成。

虽然API 手册上说 强烈建议使用Destroy代替。但是当我们使用了Destory 程序果断卡死了,可能就是因为 “实际物体的销毁总是延迟到当前更新循环后”,所以导致了该问题,所以这里暂时还是尽量去使用 DestroyImmediate 。

排序:
UIGrid 自身的排序方式就有几种,不过我没有用,因为是要根据例如 装备的各项属性进行排序,其实就是在第一步的加载那里,有一个 读取 List 表,然后将 List 表中的内容 逐一加入到 UIGrid 当中,那么 List表的读取顺序,就是加载的顺序了。
UIGrid 设置排序方式的官方接口 有一个 Custom 方式,貌似要重载方法去重写排序方法,好像有点小麻烦 ~ 
我们只要在 List 中提前按照我们想要的顺序进行一遍排序(比如用冒泡,快速,归并什么的 算法就自己根据需要决定了),然后直接进行 UIGrid 的加载就是我们想要的顺序了~

上面有些院里解释还不是很清楚,是因为我也没明白的很详细,待完全弄明白了会继续更新的~ 暂时应该是可以帮助到需要用这个知识点的开发者的。
如果有大神 愿意赐教,我不胜感激!!!

初学者一名,只是想把自己遇到的问题的解决方案写上来,自己留个备份,也可以帮助其他初学者。
可能问题过于简单,希望大神勿喷,有错误还请各位指出,十分感谢。

如何消除排序造成的卡顿:
注:排序时候由于 Item 较多,销毁后在将排序好的 List 重新加载会非常卡顿,用户体验十分差;替换元素其实也比较浪费时间和代码量,所以这里我们找到了更为便捷的解决方案。
UIGrid 的默认排序方式就是按照 UIGrid 里面的 Item 名称进行排序,所以比如我要以 Item 的级别进行排序的话, 我们只需要得到 Item控件,然后将 Item 的控件名称修改为 级别名称,然后调用刷新 UIGrid ,他就会自动按照名字的顺序进行排序了,已经过试验,毫无卡顿现象。

代码如下~ 
[/color][/color][color=#000000]public void sortWeight()
{
    for (int i = 0; i < itemData.Item_List.Count; i++)
    {
        ItemDataManager ItemTable = itemData.Item_List[i];
        grid.transform.GetChild(i).GetComponentInChildren<Item>().name = ItemIndex.getItem_weight(grid.transform.GetChild(i).GetComponentInChildren<Item>().item_id).ToString();
    }
         
        //列表添加后用于刷新listView
        grid.repositionNow = true;
        grid.maxPerLine = 5;
        //重设uigrid
        grid.sorted = true;
        grid.Reposition();
}

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引