界面组件导出工具

This commit is contained in:
2025-07-20 01:24:55 +08:00
parent 645d57c7c9
commit 91fd6d30a1
12 changed files with 234 additions and 49 deletions

View File

@@ -0,0 +1,145 @@
using System.Linq;
using UnityEditor;
using UnityEngine;
using CreatGame.UI;
using UnityEditorInternal;
using Unity.VisualScripting;
using System.Collections.Generic;
[CustomEditor(typeof(UIComponentExport))]
public class UIComponentExportEditor : Editor
{
private ReorderableList reorderableList;
private void InitReorderableList()
{
reorderableList = new ReorderableList(
serializedObject,
serializedObject.FindProperty("entries"),
true, true, true, true);
reorderableList.drawHeaderCallback = (Rect rect) => { EditorGUI.LabelField(rect, "UI Prefab Entries"); };
reorderableList.elementHeightCallback = (int index) => { return EditorGUIUtility.singleLineHeight + 6f; };
reorderableList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
{
SerializedProperty element = reorderableList.serializedProperty.GetArrayElementAtIndex(index);
// drawElementCallback 中的内容
SerializedProperty keyProp = element.FindPropertyRelative("key");
SerializedProperty prefabProp = element.FindPropertyRelative("prefab");
SerializedProperty selectedNameProp = element.FindPropertyRelative("selectedComponentName");
GameObject prefab = prefabProp.objectReferenceValue as GameObject;
// 查找组件类型
List<string> uguiComponentNames = new List<string>();
if (prefab != null)
{
var components = prefab.GetComponents<Component>();
uguiComponentNames = prefab.GetComponents<Component>()
.Where(c => c != null && UIViewExportEditor.IsUGUIComponent(c))
.Select(c => c.GetType().Name)
.Distinct()
.ToList();
}
float lineHeight = EditorGUIUtility.singleLineHeight;
float padding = 4f;
float thirdWidth = (rect.width - 2 * padding) / 3f;
Rect keyRect = new Rect(rect.x, rect.y + 2, thirdWidth, lineHeight);
Rect prefabRect = new Rect(rect.x + thirdWidth + padding, rect.y + 2, thirdWidth, lineHeight);
Rect popupRect = new Rect(rect.x + 2 * (thirdWidth + padding), rect.y + 2, thirdWidth, lineHeight);
// key 字段
EditorGUI.PropertyField(keyRect, keyProp, GUIContent.none);
// prefab 字段
EditorGUI.PropertyField(prefabRect, prefabProp, GUIContent.none);
// 下拉框
if (uguiComponentNames.Count > 0)
{
int selectedIndex = Mathf.Max(0, uguiComponentNames.IndexOf(selectedNameProp.stringValue));
selectedIndex = EditorGUI.Popup(popupRect, selectedIndex, uguiComponentNames.ToArray());
selectedNameProp.stringValue = uguiComponentNames[selectedIndex];
}
else
{
EditorGUI.LabelField(popupRect, "无UGUI组件");
}
};
}
public override void OnInspectorGUI()
{
serializedObject.Update();
if (reorderableList == null)
{
InitReorderableList();
}
reorderableList?.DoLayoutList();
serializedObject.ApplyModifiedProperties();
if (GUILayout.Button("导出代码"))
{
ExportCode();
}
}
/// <summary>
/// 导出代码
/// </summary>
private void ExportCode()
{
string savePath = Application.dataPath + "/Scripts/GameLogic/Export/UGUI/";
if (string.IsNullOrEmpty(savePath))
return;
string className = $"UI{target.GameObject().name}";
string filename = System.IO.Path.Combine(savePath, $"{className}.cs");
var sb = new System.Text.StringBuilder();
sb.AppendLine("using UnityEngine;");
sb.AppendLine("using UnityEngine.UI;");
sb.AppendLine();
sb.AppendLine("namespace CreatGame.UI");
sb.AppendLine("{");
sb.AppendLine($" public partial class {className} : UIComponentBase");
sb.AppendLine(" {");
sb.AppendLine($" public override string PrefabPath => \"Prefabs/UI/{target.GameObject().name}\";");
// 字段定义
for (int i = 0; i < reorderableList.count; i++)
{
SerializedProperty element = reorderableList.serializedProperty.GetArrayElementAtIndex(i);
sb.AppendLine(" /// <summary>");
sb.AppendLine(" /// ");
sb.AppendLine(" /// </summary>");
sb.AppendLine($" public {element.FindPropertyRelative("selectedComponentName").stringValue} {element.FindPropertyRelative("key").stringValue};");
}
sb.AppendLine(" public override void PreLoad(GameObject view)");
sb.AppendLine(" {");
sb.AppendLine(" base.PreLoad(view);");
sb.AppendLine();
for (int i = 0; i < reorderableList.count; i++)
{
SerializedProperty element = reorderableList.serializedProperty.GetArrayElementAtIndex(i);
var filedName = element.FindPropertyRelative("key").stringValue;
var typeName = element.FindPropertyRelative("selectedComponentName").stringValue;
sb.AppendLine($" {filedName} = GetGameObject(nameof({filedName})).GetComponent<{typeName}>();");
}
sb.AppendLine(" }");
sb.AppendLine(" }");
sb.AppendLine("}");
Debug.Log(sb.ToString());
System.IO.File.WriteAllText(filename, sb.ToString());
Debug.Log($"✅ 导出成功:{filename}");
AssetDatabase.Refresh();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 75e425207f8b4c369bf1a58bd14d8cb4
timeCreated: 1752945208

View File

@@ -8,8 +8,8 @@ using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
[CustomEditor(typeof(UIExportTool))] [CustomEditor(typeof(UIViewExport))]
public class UIExportToolEditor : Editor public class UIViewExportEditor : Editor
{ {
private ReorderableList reorderableList; private ReorderableList reorderableList;
@@ -104,7 +104,7 @@ public class UIExportToolEditor : Editor
/// <summary> /// <summary>
/// 判断是否是常见UGUI组件你可以自行扩展 /// 判断是否是常见UGUI组件你可以自行扩展
/// </summary> /// </summary>
private bool IsUGUIComponent(Component component) public static bool IsUGUIComponent(Component component)
{ {
return component is Graphic // 基类,包含 Image、Text、RawImage return component is Graphic // 基类,包含 Image、Text、RawImage
|| component is Button || component is Button

View File

@@ -0,0 +1,12 @@
using UnityEngine;
namespace CreatGame.UI
{
/// <summary>
/// 通用的导出预制件的基类
/// </summary>
public class UIComponentBase : MonoBehaviour
{
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ba52eedd767b46ae90e720030c75503f
timeCreated: 1752945611

View File

@@ -16,7 +16,7 @@ namespace CreatGame.UI
/// <summary> /// <summary>
/// 导出脚本 /// 导出脚本
/// </summary> /// </summary>
protected UIExportTool m_ExportTool; protected UIViewExport MViewExport;
/// <summary> /// <summary>
/// 是否加载完成 /// 是否加载完成
/// </summary> /// </summary>
@@ -27,7 +27,7 @@ namespace CreatGame.UI
public virtual void PreLoad(GameObject viewObject) public virtual void PreLoad(GameObject viewObject)
{ {
m_ViewObject = viewObject; m_ViewObject = viewObject;
m_ExportTool = viewObject.GetComponent<UIExportTool>(); MViewExport = viewObject.GetComponent<UIViewExport>();
IsPreLoad = true; IsPreLoad = true;
} }
/// <summary> /// <summary>
@@ -47,11 +47,11 @@ namespace CreatGame.UI
protected GameObject GetGameObject(string name) protected GameObject GetGameObject(string name)
{ {
for (int i = 0; i < m_ExportTool.entries.Count; i++) for (int i = 0; i < MViewExport.entries.Count; i++)
{ {
if (m_ExportTool.entries[i].key == name) if (MViewExport.entries[i].key == name)
{ {
return m_ExportTool.entries[i].prefab; return MViewExport.entries[i].prefab;
} }
} }

View File

@@ -0,0 +1,19 @@
using System;
using UnityEngine;
using System.Collections.Generic;
namespace CreatGame.UI
{
public class UIComponentExport : MonoBehaviour
{
[Serializable]
public class UIEntry
{
public string key;
public GameObject prefab;
public string selectedComponentName; // 存储选择的组件类型名
}
public List<UIEntry> entries = new List<UIEntry>();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d94101161a144f17b4b80530abe93975
timeCreated: 1752945103

View File

@@ -2,7 +2,7 @@ using System;
using UnityEngine; using UnityEngine;
using System.Collections.Generic; using System.Collections.Generic;
public class UIExportTool : MonoBehaviour public class UIViewExport : MonoBehaviour
{ {
[Serializable] [Serializable]
public class UIEntry public class UIEntry

View File

@@ -19,7 +19,7 @@ MonoBehaviour:
width: 2048 width: 2048
height: 1060.8 height: 1060.8
m_ShowMode: 4 m_ShowMode: 4
m_Title: Project m_Title: Inspector
m_RootView: {fileID: 7} m_RootView: {fileID: 7}
m_MinSize: {x: 875, y: 300} m_MinSize: {x: 875, y: 300}
m_MaxSize: {x: 10000, y: 10000} m_MaxSize: {x: 10000, y: 10000}
@@ -41,7 +41,7 @@ MonoBehaviour:
serializedVersion: 2 serializedVersion: 2
x: 0 x: 0
y: 0 y: 0
width: 398.4 width: 372
height: 358.80005 height: 358.80005
m_MinSize: {x: 231, y: 271} m_MinSize: {x: 231, y: 271}
m_MaxSize: {x: 10001, y: 10021} m_MaxSize: {x: 10001, y: 10021}
@@ -74,7 +74,7 @@ MonoBehaviour:
m_MinSize: {x: 200, y: 50} m_MinSize: {x: 200, y: 50}
m_MaxSize: {x: 16192, y: 8096} m_MaxSize: {x: 16192, y: 8096}
vertical: 0 vertical: 0
controlID: 92 controlID: 84
draggingID: 0 draggingID: 0
--- !u!114 &4 --- !u!114 &4
MonoBehaviour: MonoBehaviour:
@@ -91,9 +91,9 @@ MonoBehaviour:
m_Children: [] m_Children: []
m_Position: m_Position:
serializedVersion: 2 serializedVersion: 2
x: 398.4 x: 372
y: 0 y: 0
width: 1649.6 width: 1676
height: 358.80005 height: 358.80005
m_MinSize: {x: 101, y: 121} m_MinSize: {x: 101, y: 121}
m_MaxSize: {x: 4001, y: 4021} m_MaxSize: {x: 4001, y: 4021}
@@ -126,7 +126,7 @@ MonoBehaviour:
m_MinSize: {x: 300, y: 100} m_MinSize: {x: 300, y: 100}
m_MaxSize: {x: 24288, y: 16192} m_MaxSize: {x: 24288, y: 16192}
vertical: 1 vertical: 1
controlID: 91 controlID: 83
draggingID: 0 draggingID: 0
--- !u!114 &6 --- !u!114 &6
MonoBehaviour: MonoBehaviour:
@@ -229,7 +229,7 @@ MonoBehaviour:
m_MinSize: {x: 300, y: 50} m_MinSize: {x: 300, y: 50}
m_MaxSize: {x: 24288, y: 8096} m_MaxSize: {x: 24288, y: 8096}
vertical: 0 vertical: 0
controlID: 38 controlID: 48
draggingID: 0 draggingID: 0
--- !u!114 &10 --- !u!114 &10
MonoBehaviour: MonoBehaviour:
@@ -325,9 +325,9 @@ MonoBehaviour:
m_Tooltip: m_Tooltip:
m_Pos: m_Pos:
serializedVersion: 2 serializedVersion: 2
x: -1649.6 x: -1676
y: 725.60004 y: 725.60004
width: 1648.6 width: 1675
height: 337.80005 height: 337.80005
m_SerializedDataModeController: m_SerializedDataModeController:
m_DataMode: 0 m_DataMode: 0
@@ -376,9 +376,9 @@ MonoBehaviour:
m_SceneHierarchy: m_SceneHierarchy:
m_TreeViewState: m_TreeViewState:
scrollPos: {x: 0, y: 0} scrollPos: {x: 0, y: 0}
m_SelectedIDs: 0a5f0000 m_SelectedIDs: 00600000
m_LastClickedID: 0 m_LastClickedID: 0
m_ExpandedIDs: 0cfaffff m_ExpandedIDs: 9e62ffff6e63ffff3c65ffff96beffff9cbeffffa4beffffbebeffffd2c5ffffd8c5ffffe0c5fffffac5ffffdcc7ffffe2c7ffffeac7ffff04c8ffff3eccffff44ccffff4cccffff66ccffff16d2ffff1cd2ffff24d2ffff3ed2ffffaee1ffffb4e1ffffbce1ffffd6e1ffffd0e4ffffe2e6ffff78e7ffff7ee7ffff86e7ffffa0e7ffffeeeeffff08efffff20efffff26efffff2eefffff2cfbfffff4ffffff4e5f00005e5f0000785f0000865f00008a5f00002863000038630000526300006063000064630000
m_RenameOverlay: m_RenameOverlay:
m_UserAcceptedRename: 0 m_UserAcceptedRename: 0
m_Name: m_Name:
@@ -471,7 +471,7 @@ MonoBehaviour:
serializedVersion: 2 serializedVersion: 2
x: -2048 x: -2048
y: 725.60004 y: 725.60004
width: 397.4 width: 371
height: 337.80005 height: 337.80005
m_SerializedDataModeController: m_SerializedDataModeController:
m_DataMode: 0 m_DataMode: 0
@@ -494,7 +494,7 @@ MonoBehaviour:
m_SkipHidden: 0 m_SkipHidden: 0
m_SearchArea: 1 m_SearchArea: 1
m_Folders: m_Folders:
- Assets/Scripts/ThirdParty/LoopList/Runtime - Assets/Scripts/GameTools
m_Globs: [] m_Globs: []
m_OriginalText: m_OriginalText:
m_ImportLogFlags: 0 m_ImportLogFlags: 0
@@ -510,7 +510,7 @@ MonoBehaviour:
scrollPos: {x: 0, y: 0} scrollPos: {x: 0, y: 0}
m_SelectedIDs: b2df0000 m_SelectedIDs: b2df0000
m_LastClickedID: 57266 m_LastClickedID: 57266
m_ExpandedIDs: 00000000fc5f0000fe5f000000600000026000000460000006600000086000000a6000000c6000000e6000001060000012600000146000001660000018600000 m_ExpandedIDs: 00000000ba5f0000bc5f0000be5f0000c05f0000c25f0000c45f0000c65f0000c85f0000ca5f0000cc5f0000
m_RenameOverlay: m_RenameOverlay:
m_UserAcceptedRename: 0 m_UserAcceptedRename: 0
m_Name: m_Name:
@@ -535,24 +535,24 @@ MonoBehaviour:
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_ResourceFile: m_ResourceFile:
m_AssetTreeState: m_AssetTreeState:
scrollPos: {x: 0, y: 172.19995} scrollPos: {x: 0, y: 0}
m_SelectedIDs: m_SelectedIDs:
m_LastClickedID: 0 m_LastClickedID: 0
m_ExpandedIDs: ffffffff00000000ca5e0000d25e0000fc5f0000fe5f00000260000004600000066000000c6000000e60000054600000 m_ExpandedIDs: ffffffff00000000ba5f0000be5f0000c05f0000c25f0000c45f0000c65f0000c85f0000ca5f0000cc5f0000f85f0000fc5f00005460000058600000ffffff7f
m_RenameOverlay: m_RenameOverlay:
m_UserAcceptedRename: 0 m_UserAcceptedRename: 0
m_Name: m_Name: MainView
m_OriginalName: m_OriginalName: MainView
m_EditFieldRect: m_EditFieldRect:
serializedVersion: 2 serializedVersion: 2
x: 0 x: 0
y: 0 y: 0
width: 0 width: 0
height: 0 height: 0
m_UserData: 0 m_UserData: 24592
m_IsWaitingForDelay: 0 m_IsWaitingForDelay: 0
m_IsRenaming: 0 m_IsRenaming: 0
m_OriginalEventType: 11 m_OriginalEventType: 0
m_IsRenamingFilename: 1 m_IsRenamingFilename: 1
m_ClientGUIView: {fileID: 2} m_ClientGUIView: {fileID: 2}
m_SearchString: m_SearchString:
@@ -634,7 +634,7 @@ MonoBehaviour:
m_ShowGizmos: 0 m_ShowGizmos: 0
m_TargetDisplay: 0 m_TargetDisplay: 0
m_ClearColor: {r: 0, g: 0, b: 0, a: 0} m_ClearColor: {r: 0, g: 0, b: 0, a: 0}
m_TargetSize: {x: 1920, y: 1080} m_TargetSize: {x: 1280, y: 720}
m_TextureFilterMode: 0 m_TextureFilterMode: 0
m_TextureHideFlags: 61 m_TextureHideFlags: 61
m_RenderIMGUI: 1 m_RenderIMGUI: 1
@@ -643,16 +643,16 @@ MonoBehaviour:
m_VSyncEnabled: 0 m_VSyncEnabled: 0
m_Gizmos: 0 m_Gizmos: 0
m_Stats: 0 m_Stats: 0
m_SelectedSizes: 03000000000000000000000000000000000000000000000000000000000000000000000000000000 m_SelectedSizes: 07000000000000000000000000000000000000000000000000000000000000000000000000000000
m_ZoomArea: m_ZoomArea:
m_HRangeLocked: 0 m_HRangeLocked: 0
m_VRangeLocked: 0 m_VRangeLocked: 0
hZoomLockedByDefault: 0 hZoomLockedByDefault: 0
vZoomLockedByDefault: 0 vZoomLockedByDefault: 0
m_HBaseRangeMin: -768 m_HBaseRangeMin: -512
m_HBaseRangeMax: 768 m_HBaseRangeMax: 512
m_VBaseRangeMin: -432 m_VBaseRangeMin: -288
m_VBaseRangeMax: 432 m_VBaseRangeMax: 288
m_HAllowExceedBaseRangeMin: 1 m_HAllowExceedBaseRangeMin: 1
m_HAllowExceedBaseRangeMax: 1 m_HAllowExceedBaseRangeMax: 1
m_VAllowExceedBaseRangeMin: 1 m_VAllowExceedBaseRangeMin: 1
@@ -672,7 +672,7 @@ MonoBehaviour:
y: 21 y: 21
width: 1051.6 width: 1051.6
height: 610 height: 610
m_Scale: {x: 0.6846354, y: 0.6846354} m_Scale: {x: 1, y: 1}
m_Translation: {x: 525.8, y: 305} m_Translation: {x: 525.8, y: 305}
m_MarginLeft: 0 m_MarginLeft: 0
m_MarginRight: 0 m_MarginRight: 0
@@ -680,12 +680,12 @@ MonoBehaviour:
m_MarginBottom: 0 m_MarginBottom: 0
m_LastShownAreaInsideMargins: m_LastShownAreaInsideMargins:
serializedVersion: 2 serializedVersion: 2
x: -768 x: -525.8
y: -445.49258 y: -305
width: 1536 width: 1051.6
height: 890.98517 height: 610
m_MinimalGUI: 1 m_MinimalGUI: 1
m_defaultScale: 0.6846354 m_defaultScale: 1
m_LastWindowPixelSize: {x: 1314.5, y: 788.75} m_LastWindowPixelSize: {x: 1314.5, y: 788.75}
m_ClearInEditMode: 1 m_ClearInEditMode: 1
m_NoCameraWarning: 1 m_NoCameraWarning: 1
@@ -1061,9 +1061,9 @@ MonoBehaviour:
m_PlayAudio: 0 m_PlayAudio: 0
m_AudioPlay: 0 m_AudioPlay: 0
m_Position: m_Position:
m_Target: {x: -3.6708412, y: -4.282875, z: 44.11006} m_Target: {x: -3.4252472, y: 4.8869476, z: 122.382324}
speed: 2 speed: 2
m_Value: {x: 555.8997, y: 291.5927, z: -0.53083503} m_Value: {x: -3.4252472, y: 4.8869476, z: 122.382324}
m_RenderMode: 0 m_RenderMode: 0
m_CameraMode: m_CameraMode:
drawMode: 0 drawMode: 0
@@ -1101,7 +1101,7 @@ MonoBehaviour:
m_Fade: m_Fade:
m_Target: 0 m_Target: 0
speed: 2 speed: 2
m_Value: 1 m_Value: 0
m_Color: {r: 0.5, g: 0.5, b: 0.5, a: 0.4} m_Color: {r: 0.5, g: 0.5, b: 0.5, a: 0.4}
m_Pivot: {x: 0, y: 0, z: 0} m_Pivot: {x: 0, y: 0, z: 0}
m_Size: {x: 1, y: 1} m_Size: {x: 1, y: 1}
@@ -1109,13 +1109,13 @@ MonoBehaviour:
m_GridAxis: 1 m_GridAxis: 1
m_gridOpacity: 0.5 m_gridOpacity: 0.5
m_Rotation: m_Rotation:
m_Target: {x: -0.25270963, y: 0.65854186, z: -0.25104713, w: -0.6629036} m_Target: {x: -0.15744555, y: 0.8125271, z: -0.25616828, w: -0.4993938}
speed: 2 speed: 2
m_Value: {x: 0, y: 0, z: 0, w: 1} m_Value: {x: -0.1574451, y: 0.8125248, z: -0.25616753, w: -0.49939236}
m_Size: m_Size:
m_Target: 53.034447 m_Target: 24.276482
speed: 2 speed: 2
m_Value: 522.41943 m_Value: 24.276482
m_Ortho: m_Ortho:
m_Target: 0 m_Target: 0
speed: 2 speed: 2
@@ -1133,7 +1133,7 @@ MonoBehaviour:
m_FarClip: 10000 m_FarClip: 10000
m_DynamicClip: 1 m_DynamicClip: 1
m_OcclusionCulling: 0 m_OcclusionCulling: 0
m_LastSceneViewRotation: {x: -0.08717229, y: 0.89959055, z: -0.21045254, w: -0.3726226} m_LastSceneViewRotation: {x: -0.15744555, y: 0.8125271, z: -0.25616828, w: -0.4993938}
m_LastSceneViewOrtho: 0 m_LastSceneViewOrtho: 0
m_ReplacementShader: {fileID: 0} m_ReplacementShader: {fileID: 0}
m_ReplacementString: m_ReplacementString: