Odin Inspector 系列教程 ---【小工具】UGUI節點收集器(UINodeCollection)

本工具是基于Odin制作,方便查找對應面板的UGUI組件,并提供對應腳本創建、組件賦值、常規沖突檢測等機制。
方便快捷易上手,筆者已經做好注釋,易于魔改。(例如生成Lua文件等)。

選擇要添加的類型

添加對應類型的節點,不符合類型會報錯

選擇UI分部類對應的腳本文件

點擊【導出對應分部類】按鈕,節點出現重名會有提示

點擊【為組件進行賦值】按鈕進行綁定


示例完整腳本

using Sirenix.OdinInspector;
using Sirenix.Utilities;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.UI;

public class UINodeCollection : MonoBehaviour
{
    [SerializeField]
    [ListDrawerSettings(DraggableItems = false, Expanded = false)]
    private List<UINodeGroup> uINodes = new List<UINodeGroup>();


    #region 編輯器

#if UNITY_EDITOR
    const string k_Tab = "    ";
    public string className;

#pragma warning disable CS0649
    [ShowInInspector]
    [LabelText("選擇需要生成的分部類")]
    [FilePath(Extensions = "cs, lua", AbsolutePath = true)]
    private string filePath;
#pragma warning restore CS0649

    [Button("導出對應的分部類", ButtonSizes.Large)]
    private void ExportPartialScript()
    {
        if (string.IsNullOrEmpty(filePath))
        {
            UnityEditor.EditorUtility.DisplayDialog("警告", "沒有選擇需要生成的分部類", "確定");
            return;
        }
        if (IsHaveRepetitiveName()) return;

        //獲取對應的類名稱
        var layerArray = filePath.Split(Path.AltDirectorySeparatorChar);
        className = layerArray[layerArray.Length - 1].Split('.')[0];
        //生成絕對路徑
        string path = filePath.Replace(className, className + "Extention");

        StringBuilder content = new StringBuilder();
        //添加對應的注釋
        content.AppendLine(CreateAnnotation().ToString());
        //添加命名空間
        content.Append(AdditionalNamespacesToString());
        //添加內容
        content.AppendLine("public partial class " + className + "\r\n" + "{\r\n");
        for (int i = 0; i < uINodes.Count; i++)
        {
            content.AppendLine(CreateOneGroup(uINodes[i]));
        }
        content.AppendLine("}\r\n");

        CreateScript(path, content);
        UnityEditor.AssetDatabase.Refresh();
        Debug.Log("生成代碼完畢");
    }

    [Button("為組件進行賦值", ButtonSizes.Large)]
    private void SetComponentValue()
    {
        string nameSpace = "Assembly-CSharp";
        var assembly = Assembly.Load(nameSpace);
        var tempType = assembly.GetType(className);
        var type = transform.GetComponent(tempType);
        var fieldInfos = type.GetType().GetFields();

        for (int i = 0; i < fieldInfos.Length; i++)
        {
            var item = fieldInfos[i];
            var targetType = item.FieldType;

            var temp = uINodes.Where(a => a.typeName == targetType.Name)//篩選類型
                .SelectMany(a => a.nodes)
                .Where(t => t.name.Replace(" ", "") == item.Name)
                .FirstOrDefault();
            var targetValue = temp.gameObject.GetComponent(targetType);
            item.SetValue(type, targetValue);
        }
    }

    private StringBuilder CreateAnnotation()
    {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.AppendLine("http://開發者:海瀾");
        stringBuilder.AppendLine("http://描述:快速查找對應UI組件節點及代碼綁定");
        stringBuilder.AppendLine("http://腳本創建時間:" + DateTime.Now);
        stringBuilder.AppendLine(
@"http://********************************
//本腳本為自動創建【切勿更改】
//********************************");
        return stringBuilder;
    }
    private string AdditionalNamespacesToString()
    {
        return
            "using System;\r\n" +
            "using System.Collections;\r\n" +
            "using System.Collections.Generic;\r\n" +
            "using System.IO;\r\n" +
            "using System.Linq;\r\n" +
            "using UnityEngine;\r\n" +
            "using UnityEngine.UI;\r\n" +
            "using Sirenix.OdinInspector; \r\n" +
            "using TMPro; \r\n" +
            "\r\n";
    }
    private string CreateOneGroup(UINodeGroup uINodeGroup)
    {
        string temp = "";
        var nodes = uINodeGroup.nodes;
        string typeName = uINodeGroup.typeName;
        for (int i = 0; i < nodes.Count; i++)
        {
            temp += k_Tab + $"public {typeName} {nodes[i].name.Replace(" ", "")};\r\n";
        }
        return temp;
    }
    private void CreateScript(string fileName, StringBuilder content)
    {
        string path = fileName;

        using (FileStream fs = new FileStream(path, FileMode.Create))
        {
            using (StreamWriter writer = new StreamWriter(fs, System.Text.Encoding.UTF8))
            {
                writer.Write(content.ToString());
            }
        }
    }

    private bool IsHaveRepetitiveName()
    {
        string content = "";
        for (int i = 0; i < uINodes.Count; i++)
        {
            content += GetRepetitiveName(uINodes[i]);
        }
        if (!string.IsNullOrEmpty(content))
        {
            UnityEditor.EditorUtility.DisplayDialog("發現重復元素", content, "確定");
            return true;
        }
        return false;
    }

    private string GetRepetitiveName(UINodeGroup uINodeGroup)
    {
        var nodes = uINodeGroup.nodes;
        //先去重復
        //然后查找對應Key的個數 ,大于1就是重復
        List<string> strList = new List<string>();
        for (int i = 0; i < nodes.Count; i++)
        {
            strList.Add(nodes[i].name);
        }

        var group = strList.GroupBy(str => str).Where(g => g.Count() > 1).Select(y => new { Element = y.Key, Counter = y.Count() }).ToList();
        string content = "";
        for (int i = 0; i < group.Count; i++)
        {
            content += $"重復元素:{group[i].Element} 重復的個數為:{group[i].Counter}";
        }
        return content;
    }


#endif

    #endregion

    [Serializable]
    private class UINodeGroup
    {
#pragma warning disable CS0649
        [LabelText("節點類型")]
        [ValueDropdown("GetFilteredTypeList")]
        public string typeName;
#pragma warning restore CS0649

        [ChildGameObjectsOnly]
        [ValidateInput("ValidateComponent", "填對對應的組件非指定類型", InfoMessageType.Error)]
        public List<UnityEngine.Component> nodes = new List<UnityEngine.Component>();

        #region 編輯器

#if UNITY_EDITOR
        /// <summary>
        /// typeName類型過濾
        /// </summary>
        /// <returns></returns>
        private IEnumerable<string> GetFilteredTypeList()
        {
            var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes())
                .Where(t => !t.IsAbstract)
                .Where(t => !t.IsGenericTypeDefinition)
                .Where(t => typeof(Component).IsAssignableFrom(t))
                .Where(t => t.Namespace == "UnityEngine.UI")
                .Where(t => t.IsPublic);

            types = types.AppendWith(typeof(Transform));

            var typeNames = types.Select(t => t.Name);
            return typeNames;
        }

        /// <summary>
        /// 對添加節點類型的驗證
        /// </summary>
        /// <param name="nodes"></param>
        /// <returns></returns>
        private bool ValidateComponent(List<UnityEngine.Component> nodes)
        {
            if (nodes.Count <= 0 || typeName == "Transform") return true;

            string nameSpace = "UnityEngine.UI";
            var node = nodes[nodes.Count - 1];

            var assembly = Assembly.Load(nameSpace);
            var tempType = assembly.GetType(nameSpace + "." + typeName);
            var tempComponent = node.GetComponent(tempType);

            return tempComponent != null;
        }
#endif

        #endregion
    }

}

更多教程內容詳見:革命性Unity 編輯器擴展工具 --- Odin Inspector 系列教程

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。