From 4de5156174588992d1bfd4222256ed54f02e8394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=80=9D=E6=B5=B7?= <1464576565@qq.com> Date: Wed, 12 Nov 2025 17:48:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=94=9F=E6=88=90=E7=94=A8?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GenerateWindow/UISettingEditorWindow.cs | 23 +-- Editor/UI/Helper/UIScriptGeneratorHelper.cs | 151 +++++++----------- Editor/UI/Res/UITemplate.txt | 15 ++ Editor/UI/Res/UITemplate.txt.meta | 3 + Editor/UI/UIConfig/UIGenerateConfiguration.cs | 8 - Editor/UI/UIConfig/UIGlobalPath.cs | 1 + 6 files changed, 76 insertions(+), 125 deletions(-) create mode 100644 Editor/UI/Res/UITemplate.txt create mode 100644 Editor/UI/Res/UITemplate.txt.meta diff --git a/Editor/UI/GenerateWindow/UISettingEditorWindow.cs b/Editor/UI/GenerateWindow/UISettingEditorWindow.cs index 4ef9919..f8a492b 100644 --- a/Editor/UI/GenerateWindow/UISettingEditorWindow.cs +++ b/Editor/UI/GenerateWindow/UISettingEditorWindow.cs @@ -34,7 +34,6 @@ namespace AlicizaX.UI.Editor private readonly string[] toolbarTitles = { "UI基础设置", "UI构建配置", "UI元素映射" }; - private ReorderableList combineList; private ReorderableList regexList; private ReorderableList projectList; private ReorderableList excludeList; @@ -70,22 +69,6 @@ namespace AlicizaX.UI.Editor private void SetupLists() { - combineList = new ReorderableList(UIGenerateCommonData.CombineWords, typeof(StringPair), true, true, true, true); - combineList.drawHeaderCallback = (r) => EditorGUI.LabelField(r, "路径拼接映射 (Key -> Value)"); - combineList.drawElementCallback = (rect, index, active, focused) => - { - var p = UIGenerateCommonData.CombineWords[index]; - rect.y += 2; - float half = rect.width / 2 - 8; - p.Key = EditorGUI.TextField(new Rect(rect.x, rect.y, half, EditorGUIUtility.singleLineHeight), p.Key); - p.Value = EditorGUI.TextField(new Rect(rect.x + half + 16, rect.y, half, EditorGUIUtility.singleLineHeight), p.Value); - }; - combineList.onAddCallback = (r) => UIGenerateCommonData.CombineWords.Add(new StringPair("Key", "Value")); - combineList.onRemoveCallback = (r) => - { - if (r.index >= 0) UIGenerateCommonData.CombineWords.RemoveAt(r.index); - }; - excludeList = new ReorderableList(excludeKeywordsList, typeof(string), true, true, true, true); excludeList.drawHeaderCallback = (r) => EditorGUI.LabelField(r, "排除关键字(匹配则不生成)"); @@ -269,7 +252,7 @@ namespace AlicizaX.UI.Editor UIGenerateCommonData.ComCheckEndName = EditorGUILayout.TextField(new GUIContent("组件结尾分隔符", "例如 @End"), UIGenerateCommonData.ComCheckEndName); UIGenerateCommonData.ArrayComSplitName = EditorGUILayout.TextField(new GUIContent("数组组件分隔符", "例如 *Item"), UIGenerateCommonData.ArrayComSplitName); UIGenerateCommonData.GeneratePrefix = EditorGUILayout.TextField(new GUIContent("生成脚本前缀"), UIGenerateCommonData.GeneratePrefix); - m_ScriptGeneratorHelperSelectIndex = EditorGUILayout.Popup("解密服务", m_ScriptGeneratorHelperSelectIndex, m_ScriptGeneratorHelperTypes.ToArray()); + m_ScriptGeneratorHelperSelectIndex = EditorGUILayout.Popup("UI辅助生成", m_ScriptGeneratorHelperSelectIndex, m_ScriptGeneratorHelperTypes.ToArray()); string selectService = m_ScriptGeneratorHelperTypes[m_ScriptGeneratorHelperSelectIndex]; if (uiGenerateConfiguration.UIScriptGeneratorRuleHelper != selectService) { @@ -283,10 +266,6 @@ namespace AlicizaX.UI.Editor excludeList.DoLayoutList(); - GUILayout.Space(8); - - combineList.DoLayoutList(); - EditorGUILayout.Space(8); EditorGUILayout.LabelField("脚本生成预览", EditorStyles.boldLabel); diff --git a/Editor/UI/Helper/UIScriptGeneratorHelper.cs b/Editor/UI/Helper/UIScriptGeneratorHelper.cs index 5ff728f..10ea07b 100644 --- a/Editor/UI/Helper/UIScriptGeneratorHelper.cs +++ b/Editor/UI/Helper/UIScriptGeneratorHelper.cs @@ -95,7 +95,7 @@ namespace AlicizaX.UI.Editor } } - private static string GetVersionType(string uiName) + private static string GetUIElementComponentType(string uiName) { if (string.IsNullOrEmpty(uiName)) return string.Empty; foreach (var pair in UIConfiguration.UIElementRegexConfigs ?? Enumerable.Empty()) @@ -127,7 +127,7 @@ namespace AlicizaX.UI.Editor return comStr.Split(new[] { split }, StringSplitOptions.RemoveEmptyEntries); } - private static string GetKeyName(string key, string componentName, EBindType bindType) + private static string GetVariableName(string key, string componentName, EBindType bindType) { var helper = UIGeneratorRuleHelper; if (helper == null) @@ -206,13 +206,13 @@ namespace AlicizaX.UI.Editor foreach (var com in componentArray) { if (string.IsNullOrEmpty(com)) continue; - string typeName = GetVersionType(com); + string typeName = GetUIElementComponentType(com); if (string.IsNullOrEmpty(typeName)) continue; Component component = node.GetComponent(typeName); if (component != null) { - string keyName = GetKeyName(com, node.name, EBindType.None); + string keyName = GetVariableName(com, node.name, EBindType.None); if (_uiBindDatas.Exists(a => a.Name == keyName)) { Debug.LogError($"Duplicate key found: {keyName}"); @@ -247,7 +247,7 @@ namespace AlicizaX.UI.Editor return; } - string keyName = GetKeyName(string.Empty, node.name, EBindType.Widget); + string keyName = GetVariableName(string.Empty, node.name, EBindType.Widget); if (_uiBindDatas.Exists(a => a.Name == keyName)) { Debug.LogError($"Duplicate key found: {keyName}"); @@ -282,7 +282,7 @@ namespace AlicizaX.UI.Editor List tempBindDatas = new List(componentArray.Length); for (int i = 0; i < componentArray.Length; i++) { - string keyNamePreview = GetKeyName(componentArray[i], nodeName, EBindType.ListCom); + string keyNamePreview = GetVariableName(componentArray[i], nodeName, EBindType.ListCom); tempBindDatas.Add(new UIBindData(keyNamePreview, new List(), EBindType.ListCom)); } @@ -292,7 +292,7 @@ namespace AlicizaX.UI.Editor string com = componentArray[index]; if (string.IsNullOrEmpty(com)) continue; - string typeName = GetVersionType(com); + string typeName = GetUIElementComponentType(com); if (string.IsNullOrEmpty(typeName)) continue; foreach (var node in orderedNodes) @@ -326,32 +326,22 @@ namespace AlicizaX.UI.Editor private static string GetReferenceNamespace() { - StringBuilder sb = new StringBuilder(); - HashSet namespaces = new HashSet(StringComparer.Ordinal); + HashSet namespaceSet = new HashSet(StringComparer.Ordinal); - // 基础 namespace - namespaces.Add("UnityEngine"); - sb.AppendLine("using UnityEngine;"); - - bool needCollectionsGeneric = _uiBindDatas.Any(d => d.BindType == EBindType.ListCom); - if (needCollectionsGeneric) - { - namespaces.Add("System.Collections.Generic"); - sb.AppendLine("using System.Collections.Generic;"); - } + namespaceSet.Add("UnityEngine"); + if (_uiBindDatas.Any(d => d.BindType == EBindType.ListCom)) + namespaceSet.Add("System.Collections.Generic"); foreach (var bindData in _uiBindDatas) { - var comp = bindData.BindCom?.FirstOrDefault(); - string ns = comp?.GetType().Namespace; - if (!string.IsNullOrEmpty(ns) && !namespaces.Contains(ns)) + var ns = bindData.BindCom?.FirstOrDefault()?.GetType().Namespace; + if (!string.IsNullOrEmpty(ns) && !namespaceSet.Contains(ns)) { - namespaces.Add(ns); - sb.AppendLine($"using {ns};"); + namespaceSet.Add(ns); } } - return sb.ToString(); + return new StringBuilder().Append(string.Join(Environment.NewLine, namespaceSet.Select(n => $"using {n};"))).ToString(); } private static string GetVariableText(List uiBindDatas) @@ -362,55 +352,36 @@ namespace AlicizaX.UI.Editor var helper = UIGeneratorRuleHelper; if (helper == null) throw new InvalidOperationException("UIGeneratorRuleHelper is not configured."); - foreach (var bindData in uiBindDatas) - { - if (bindData == null) continue; - string variableName = bindData.Name; - if (string.IsNullOrEmpty(variableName)) continue; - - string publicName = helper.GetPublicComponentByNameRule(variableName); - variableTextBuilder.Append("\t\t[SerializeField]\n"); - - var firstType = bindData.BindCom?.FirstOrDefault()?.GetType(); - string typeName = firstType?.Name ?? "Component"; - - if (bindData.BindType == EBindType.None || bindData.BindType == EBindType.Widget) + var result = string.Join("\n\n", uiBindDatas + .Where(b => b != null && !string.IsNullOrEmpty(b.Name)) + .Select(b => { - variableTextBuilder.Append($"\t\tprivate {typeName} {variableName};\n"); - variableTextBuilder.Append($"\t\tpublic {typeName} {publicName} => {variableName};\n\n"); - } - else if (bindData.BindType == EBindType.ListCom) - { - int count = Math.Max(0, bindData.BindCom?.Count ?? 0); - variableTextBuilder.Append($"\t\tprivate {typeName}[] {variableName} = new {typeName}[{count}];\n"); - variableTextBuilder.Append($"\t\tpublic {typeName}[] {publicName} => {variableName};\n\n"); - } - } + string variableName = b.Name; + string publicName = helper.GetPublicComponentByNameRule(variableName); + var firstType = b.BindCom?.FirstOrDefault()?.GetType(); + string typeName = firstType?.Name ?? "Component"; - return variableTextBuilder.ToString(); + var sb = new StringBuilder(); + sb.AppendLine("\t\t[SerializeField]"); + + if (b.BindType == EBindType.None || b.BindType == EBindType.Widget) + { + sb.AppendLine($"\t\tprivate {typeName} {variableName};"); + sb.Append($"\t\tpublic {typeName} {publicName} => {variableName};"); + } + else if (b.BindType == EBindType.ListCom) + { + int count = Math.Max(0, b.BindCom?.Count ?? 0); + sb.AppendLine($"\t\tprivate {typeName}[] {variableName} = new {typeName}[{count}];"); + sb.Append($"\t\tpublic {typeName}[] {publicName} => {variableName};"); + } + + return sb.ToString(); + })); + + return variableTextBuilder.Append(result).ToString(); } - private static string GenerateScript(string className, string generateNameSpace) - { - if (string.IsNullOrEmpty(className)) throw new ArgumentNullException(nameof(className)); - if (string.IsNullOrEmpty(generateNameSpace)) throw new ArgumentNullException(nameof(generateNameSpace)); - - StringBuilder scriptBuilder = new StringBuilder(); - scriptBuilder.Append(GetReferenceNamespace()); - scriptBuilder.AppendLine("using AlicizaX.UI.Runtime;"); - scriptBuilder.AppendLine($"namespace {generateNameSpace}"); - scriptBuilder.AppendLine("{"); - scriptBuilder.AppendLine("\t#Attribute#"); - scriptBuilder.AppendLine($"\tpublic class {className} : UIHolderObjectBase"); - scriptBuilder.AppendLine("\t{"); - scriptBuilder.AppendLine("\t\tpublic const string ResTag = #Tag#;"); - scriptBuilder.AppendLine("\t\t#region Generated by Script Tool\n"); - scriptBuilder.Append(GetVariableText(_uiBindDatas)); - scriptBuilder.AppendLine("\t\t#endregion"); - scriptBuilder.AppendLine("\t}"); - scriptBuilder.AppendLine("}"); - return scriptBuilder.ToString(); - } public static void GenerateAndAttachScript(GameObject targetObject, UIScriptGenerateData scriptGenerateData) { @@ -448,15 +419,15 @@ namespace AlicizaX.UI.Editor GetBindData(targetObject.transform); - string scriptContent = GenerateScript(className, scriptGenerateData.NameSpace); - string tagName = $"\"{ruleHelper.GetUIResourceSavePath(targetObject, scriptGenerateData)}\""; + string uiTemplateText = File.ReadAllText(UIGlobalPath.TemplatePath); + uiTemplateText = uiTemplateText.Replace("#ReferenceNameSpace#", GetReferenceNamespace()); + uiTemplateText = uiTemplateText.Replace("#ClassNameSpace#", scriptGenerateData.NameSpace); + uiTemplateText = uiTemplateText.Replace("#ClassName#", className); + uiTemplateText = uiTemplateText.Replace("#TagName#", ruleHelper.GetUIResourceSavePath(targetObject, scriptGenerateData)); + uiTemplateText = uiTemplateText.Replace("#LoadType#", scriptGenerateData.LoadType.ToString()); + uiTemplateText = uiTemplateText.Replace("#Variable#", GetVariableText(_uiBindDatas)); - string uiAttribute = $"[UIRes({className}.ResTag, EUIResLoadType.{scriptGenerateData.LoadType})]"; - - scriptContent = scriptContent.Replace("#Attribute#", uiAttribute); - scriptContent = scriptContent.Replace("#Tag#", tagName); - - ruleHelper.WriteUIScriptContent(className, scriptContent, scriptGenerateData); + ruleHelper.WriteUIScriptContent(className, uiTemplateText, scriptGenerateData); } [DidReloadScripts] @@ -464,7 +435,7 @@ namespace AlicizaX.UI.Editor { if (!EditorPrefs.HasKey("Generate")) return; - + EditorPrefs.DeleteKey("Generate"); _uiBindDatas.Clear(); _arrayComponents.Clear(); @@ -474,7 +445,7 @@ namespace AlicizaX.UI.Editor if (instanceId == -1) { Debug.LogWarning("CheckHasAttach: InstanceId missing."); - EditorPrefs.DeleteKey("Generate"); + return; } @@ -483,19 +454,18 @@ namespace AlicizaX.UI.Editor if (targetObject == null) { Debug.LogWarning("UI script generation attachment object missing!"); - EditorPrefs.DeleteKey("Generate"); return; } - // 重新收集 bind 数据并附加脚本 + GetBindData(targetObject.transform); - AttachScriptToGameObject(targetObject, className); + BindScriptPropertyField(targetObject, className); Debug.Log($"Generate {className} Successfully attached to game object"); - EditorPrefs.DeleteKey("Generate"); + } - private static void AttachScriptToGameObject(GameObject targetObject, string scriptClassName) + private static void BindScriptPropertyField(GameObject targetObject, string scriptClassName) { if (targetObject == null) throw new ArgumentNullException(nameof(targetObject)); if (string.IsNullOrEmpty(scriptClassName)) throw new ArgumentNullException(nameof(scriptClassName)); @@ -512,19 +482,10 @@ namespace AlicizaX.UI.Editor continue; } - Type[] types; - try - { - types = assembly.GetTypes(); - } - catch (ReflectionTypeLoadException e) - { - types = e.Types.Where(t => t != null).ToArray(); - } + Type[] types= assembly.GetTypes(); foreach (var type in types) { - if (type == null) continue; if (!type.IsClass || type.IsAbstract) continue; if (type.Name.Equals(scriptClassName, StringComparison.Ordinal) || type.Name.Contains(scriptClassName, StringComparison.Ordinal)) diff --git a/Editor/UI/Res/UITemplate.txt b/Editor/UI/Res/UITemplate.txt new file mode 100644 index 0000000..43f2a48 --- /dev/null +++ b/Editor/UI/Res/UITemplate.txt @@ -0,0 +1,15 @@ +#ReferenceNameSpace# +using AlicizaX.UI.Runtime; +namespace #ClassNameSpace# +{ + [UIRes(#ClassName#.ResTag, EUIResLoadType.#LoadType#)] + public class #ClassName# : UIHolderObjectBase + { + public const string ResTag = "#TagName#"; + #region Generated by Script Tool + +#Variable# + + #endregion + } +} diff --git a/Editor/UI/Res/UITemplate.txt.meta b/Editor/UI/Res/UITemplate.txt.meta new file mode 100644 index 0000000..f853f95 --- /dev/null +++ b/Editor/UI/Res/UITemplate.txt.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8456fdae556b474e85de477d9e5c0b6c +timeCreated: 1762938714 \ No newline at end of file diff --git a/Editor/UI/UIConfig/UIGenerateConfiguration.cs b/Editor/UI/UIConfig/UIGenerateConfiguration.cs index 58b1047..ef0ed52 100644 --- a/Editor/UI/UIConfig/UIGenerateConfiguration.cs +++ b/Editor/UI/UIConfig/UIGenerateConfiguration.cs @@ -36,14 +36,6 @@ namespace AlicizaX.UI.Editor [Tooltip("生成脚本前缀")] public string GeneratePrefix = "ui"; [Tooltip("排除的关键字(匹配则不生成)")] public string[] ExcludeKeywords = { "ViewHolder" }; - - [Tooltip("路径拼接映射,如:Window -> Window 文件夹")] - public List CombineWords = new List() - { - new StringPair("Window", "Window"), - new StringPair("ViewHolder", "ViewHolder"), - new StringPair("Widget", "Widget"), - }; } [Serializable] diff --git a/Editor/UI/UIConfig/UIGlobalPath.cs b/Editor/UI/UIConfig/UIGlobalPath.cs index b253c28..1e4556b 100644 --- a/Editor/UI/UIConfig/UIGlobalPath.cs +++ b/Editor/UI/UIConfig/UIGlobalPath.cs @@ -4,5 +4,6 @@ namespace AlicizaX.UI.Editor { public const string DefaultComPath = "Packages/com.alicizax.unity.framework/Editor/UI/Res/default.txt"; public const string UIPrefabPath = "Packages/com.alicizax.unity.framework/Editor/UI/Res/UIRoot.prefab"; + public const string TemplatePath = "Packages/com.alicizax.unity.framework/Editor/UI/Res/UITemplate.txt"; } }