[Unity] UI Toolkit 实现一个预制体和so数据的管理窗口 DataEdtor (IMGUIContainer、ListView)

目录

前言与展示

部分源码

IMGUIContainer调用Inspector绘制

创建ListView,绑定选中资产,打开预制体的方法

创建Asset资产(so和prefab)

完整源码GitHub


前言与展示

        灵感来源于MStudio老师的麦田物语教程中的ItemEditor

        编辑器扩展的很方便,在项目中但是不够通用(需要在脚本中一个个数据绑定和回调)其实左边的ListView可以保留,右边直接用Unity默认的Inspector绘制就好了(需要用到IMGUIContainer组件),随后写好create asset和delete asset的对应方法,这样就可以管理不同的so和prefab资产。编辑器窗口见下图: 

so资产的管理: 

也可以用来管理prefab,双击左边的某一个物件可直接打开这个预制体,并显示这个预制体的monobehaviour脚本的监视器窗口。

这里展示一下其中部分源码

部分源码

IMGUIContainer调用Inspector绘制

protected virtual void ShowInspector(UnityEngine.Object uOjbect)
{
    var container = rootVisualElement.Q<IMGUIContainer>();
    container.Clear();

    this.selection = uOjbect;
    textField.value = uOjbect?.name;

    if (uOjbect == null)
        return;

    Editor editor;
    editor = Editor.CreateEditor(uOjbect);

    container.onGUIHandler = () =>
    {
        if (uOjbect != null)
        {
            //editor.DrawDefaultInspector(); //Unity默认Inspector
            editor.OnInspectorGUI(); //这个可以走Odin插件的绘制
        }
    };
}

创建ListView,绑定选中资产,打开预制体的方法

protected virtual void CreateListView<T>(List<T> resources) where T : UnityEngine.Object
{
    if (resources == null || resources.Count == 0)
        return;
    var item = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/SugarzoTool/Editor/UIBuilder/Item.uxml");

    Func<VisualElement> makeItem = () =>
    {
        return item.Instantiate();
    };
    Action<VisualElement, int> bindItem = (e, i) =>
    {
        if (i >= resources.Count || resources[i] == null)
        {
            listView.Remove(e);
            return;
        }
        e.Q<Label>().text = resources[i].name;
    };

    listView.makeItem = makeItem;
    listView.bindItem = bindItem;
    listView.itemsSource = resources;

    listView.selectionType = SelectionType.Single;

    listView.onItemsChosen += obj =>
    {
        if (obj?.First() != null && AssetDatabase.CanOpenAssetInEditor((obj.First() as UnityEngine.Object).GetInstanceID()))
        {
            AssetDatabase.OpenAsset(obj.First() as UnityEngine.Object);
            //如果当前是预制件模式
            if (PrefabUtility.IsPartOfAnyPrefab(obj.First() as UnityEngine.Object) && PrefabStageUtility.GetCurrentPrefabStage() is PrefabStage prefabStage)
            {
                ShowInspector(prefabStage.prefabContentsRoot);
            }
        }  
    };
    listView.onSelectionChange += obj =>
    {
        Selection.activeObject = obj.First() as UnityEngine.Object;
        ShowInspector(obj.First() as UnityEngine.Object);
    };
    listView.Rebuild();
}

创建Asset资产(so和prefab)

public virtual UnityEngine.Object CreateAsset()
{
    if (FileCheck() == false)
        return null;

    UnityEngine.Object obj = null;

    if(useDefaultCreateFunction)
    {
        if (assetType == AssetType.ScriptableObject)
        {
            var so = ScriptableObject.CreateInstance(assetSo.GetType());
            so.name = defaultName;
            var createPath = $"{assetsFolderPath}/{so.name}.asset";
            int tot = 0;

            while (File.Exists(createPath) && tot++ < 1000)
            {
                so.name = defaultName + tot.ToString();
                createPath = $"{assetsFolderPath}/{so.name}.asset";
            }
            AssetDatabase.CreateAsset(so, createPath);
            obj = so;
        }
        if (assetType == AssetType.Prefab)
        {
            var newGo = Instantiate(assetGo);
            newGo.name = defaultName;

            var createPath = $"{assetsFolderPath}/{newGo.name}.asset";
            int tot = 0;

            while (File.Exists(createPath) && tot++ < 1000)
            {
                newGo.name = defaultName + tot.ToString();
                createPath = $"{assetsFolderPath}/{newGo.name}.asset";
            }

            PrefabUtility.SaveAsPrefabAsset(newGo, assetsFolderPath + "/" + newGo.name + ".prefab");
            obj = PrefabUtility.LoadPrefabContents(assetsFolderPath + "/" + newGo.name + ".prefab");
            DestroyImmediate(newGo);
        }
    }

    AssetDatabase.SaveAssets();
    OnAssetCreate?.Invoke();
    OnAssetChange?.Invoke();
    return obj;

}
public virtual void DeleteAsset(string assetFilePath)
{
    if (FileCheck() == false)
        return;

    if(useDefaultDeleteFunction)
    {
        AssetDatabase.DeleteAsset(assetFilePath);
        AssetDatabase.Refresh();
    }
    OnAssetDelete?.Invoke();
    OnAssetChange?.Invoke();
}

完整源码GitHub

GitHub - sugarzo/Unity_DataEditor: 使用UI Toolkit制作的Editor编辑器,管理项目指定类型的so和prefab资源

猜你喜欢

转载自blog.csdn.net/m0_51776409/article/details/128722027