添加了默认实例场景文件,默认示例文件。

优化了属性组的界面
This commit is contained in:
2026-06-21 22:33:13 +08:00
parent 8fec3b2f9e
commit 7c2e43efbb
26 changed files with 5065 additions and 555 deletions
@@ -1,64 +1,169 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Object = UnityEngine.Object;
namespace XericUI.ReflectionUIGenerator
{
/// <summary>
/// 界面属性编组
/// 提供预制体与 UI 标记的绑定,支持全局静态访问
///
/// 将一种 C# 数据类型与一个 UI 预制体绑定,并归属于一个主题。
/// 类似 Newtonsoft.Json 的 Converter 概念 — 针对特定 Type,指定特定的 UI 模板。
///
/// 同一类型可以有多个不同 uiName/主题的重载(如 "简单输入框" vs "带标签的输入框")。
/// Manager 根据当前主题名 + 字段 Tag 自动匹配对应的编组。
///
/// 全局注册表以 themeName 为键分组管理,OnEnable/OnDisable 自动注册/注销。
/// </summary>
[Serializable]
[CreateAssetMenu(fileName = "Xeric UI avr Property group", menuName = "Xeric Library/UI Action Vessel/Reflection UI Gen/UI avr Property Group", order = 10)]
public class XuiavrgPropertyGroupScriptableObject : ScriptableObject, IList<XuiavrPropertyScriptableObject>
public class XuiavrgPropertyGroupScriptableObject : ScriptableObject
{
#region
/// <summary>
/// 全局预制体组列表
/// 所有 PropertyGroupScriptableObject 在 OnEnable 时自动注册,OnDisable 时自动注销
/// 全局预制体组字典,以主题名称为键分组
/// </summary>
internal static List<XuiavrgPropertyGroupScriptableObject> GlobalPrefabList
= new List<XuiavrgPropertyGroupScriptableObject>();
internal static Dictionary<string, List<XuiavrgPropertyGroupScriptableObject>> GlobalPrefabDict
= new Dictionary<string, List<XuiavrgPropertyGroupScriptableObject>>();
/// <summary>
/// 根据组名查找预制体
/// 根据主题名获取该主题下所有编
/// </summary>
public static XuiavrgPropertyGroupScriptableObject FindGroupByName(string groupName)
public static List<XuiavrgPropertyGroupScriptableObject> GetGroupsByTheme(string themeName)
{
return GlobalPrefabList.FirstOrDefault(g => g.groupName == groupName);
if (string.IsNullOrEmpty(themeName))
themeName = DefaultThemeName;
GlobalPrefabDict.TryGetValue(themeName, out var list);
return list ?? new List<XuiavrgPropertyGroupScriptableObject>();
}
/// <summary>
/// 查找包含指定标记的预制体
/// 根据主题名 + 标记查找编
/// </summary>
public static List<XuiavrgPropertyGroupScriptableObject> FindGroupsByTag(XuiavrgFieldTag tag)
public static XuiavrgPropertyGroupScriptableObject FindGroup(string themeName, params XuiavrgFieldTag[] tags)
{
return GlobalPrefabList.Where(g => g.supportedTags.Contains(tag)).ToList();
var groups = GetGroupsByTheme(themeName);
return groups.FirstOrDefault(g => tags.All(t => g.supportedTags.Contains(t)));
}
/// <summary>
/// 查找同时包含所有指定标记的预制体
/// 根据主题名 + UI 名称查找编
/// </summary>
public static XuiavrgPropertyGroupScriptableObject FindGroupByTags(params XuiavrgFieldTag[] tags)
public static XuiavrgPropertyGroupScriptableObject FindGroupByUiName(string themeName, string uiName)
{
return GlobalPrefabList.FirstOrDefault(g =>
tags.All(t => g.supportedTags.Contains(t)));
var groups = GetGroupsByTheme(themeName);
return groups.FirstOrDefault(g => g.uiName == uiName);
}
/// <summary>
/// 根据主题名 + 绑定类型查找所有匹配的编组
/// </summary>
public static List<XuiavrgPropertyGroupScriptableObject> FindGroupsByType(string themeName, string valueTypeName)
{
var groups = GetGroupsByTheme(themeName);
return groups.Where(g => g.valueTypeName == valueTypeName).ToList();
}
/// <summary>
/// 默认主题名称
/// </summary>
public const string DefaultThemeName = "Default";
#endregion
#region
#region
/// <summary>预制体组名称(用于 XuiavrgFieldPrefabOverride 匹配)</summary>
public string groupName;
/// <summary>
/// 主题名称。同一主题下的 UI 组件共享统一风格。
/// </summary>
[Tooltip("主题名称。同一主题下的 UI 组件共享统一风格。Manager 根据其 currentTheme 查找对应编组")]
public string themeName = DefaultThemeName;
/// <summary>此组支持的功能标记集合</summary>
/// <summary>
/// UI 个体名称。同一类型可有多个不同名称的重载。
/// 在数据字段上通过 XuiavrgFieldPrefabOverride 按此名称指定。
/// </summary>
[Tooltip("UI 个体名称。用于 XuiavrgFieldPrefabOverride 按名指定,同一类型可有多个重载")]
public string uiName = "Default";
/// <summary>
/// 此编组绑定的 C# 数据类型全名(如 System.Single、System.String
/// </summary>
[Tooltip("绑定的 C# 数据类型全名,如 System.Single、System.Boolean")]
public string valueTypeName = "System.Single";
/// <summary>
/// 解析后的类型缓存
/// </summary>
public Type ValueType
{
get
{
if (_valueType != null) return _valueType;
if (!string.IsNullOrEmpty(valueTypeName))
_valueType = Type.GetType(valueTypeName);
return _valueType;
}
}
private Type _valueType;
/// <summary>
/// 对应的 UI 预制体
/// </summary>
[Tooltip("拖入 UI 预制体,系统会自动扫描其中的 IXuiavrgFieldTagProvider 组件")]
public GameObject prefab;
/// <summary>
/// 此编组支持的 UI 功能标记集合
/// </summary>
[Tooltip("此编组包含的 UI 功能标记。Manager 根据字段 Tag 匹配对应编组")]
public List<XuiavrgFieldTag> supportedTags = new List<XuiavrgFieldTag>();
public List<XuiavrPropertyScriptableObject> propertys = new List<XuiavrPropertyScriptableObject>();
#endregion
#region + Editor
/// <summary>
/// 从预制体中自动扫描到的 IXuiavrgFieldTagProvider 组件列表(非序列化,仅供 Editor 展示)
/// </summary>
[NonSerialized]
public List<Component> detectedComponents = new List<Component>();
/// <summary>
/// 重新扫描预制体中的标记组件
/// </summary>
public void ScanPrefabComponents()
{
detectedComponents.Clear();
if (prefab == null) return;
var components = prefab.GetComponentsInChildren<Component>(true);
foreach (var comp in components)
{
if (comp is IXuiavrgFieldTagProvider tagProvider && tagProvider.EntryTag != XuiavrgFieldTag.None)
{
detectedComponents.Add(comp);
}
}
// 自动同步 supportedTags
HashSet<XuiavrgFieldTag> autoTags = new HashSet<XuiavrgFieldTag>();
foreach (var comp in detectedComponents)
{
if (comp is IXuiavrgFieldTagProvider tp && tp.EntryTag != XuiavrgFieldTag.None)
autoTags.Add(tp.EntryTag);
}
foreach (var tag in autoTags)
{
if (!supportedTags.Contains(tag))
supportedTags.Add(tag);
}
}
#endregion
@@ -66,75 +171,37 @@ namespace XericUI.ReflectionUIGenerator
void OnEnable()
{
if (!GlobalPrefabList.Contains(this))
GlobalPrefabList.Add(this);
RegisterToGlobalDict();
}
void OnDisable()
{
GlobalPrefabList.Remove(this);
UnregisterFromGlobalDict();
}
private void RegisterToGlobalDict()
{
string key = string.IsNullOrEmpty(themeName) ? DefaultThemeName : themeName;
if (!GlobalPrefabDict.TryGetValue(key, out var list))
{
list = new List<XuiavrgPropertyGroupScriptableObject>();
GlobalPrefabDict[key] = list;
}
if (!list.Contains(this))
list.Add(this);
}
private void UnregisterFromGlobalDict()
{
string key = string.IsNullOrEmpty(themeName) ? DefaultThemeName : themeName;
if (GlobalPrefabDict.TryGetValue(key, out var list))
{
list.Remove(this);
if (list.Count == 0)
GlobalPrefabDict.Remove(key);
}
}
#endregion
public IEnumerator<XuiavrPropertyScriptableObject> GetEnumerator()
{
return propertys.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)propertys).GetEnumerator();
}
public void Add(XuiavrPropertyScriptableObject item)
{
propertys.Add(item);
}
public void Clear()
{
propertys.Clear();
}
public bool Contains(XuiavrPropertyScriptableObject item)
{
return propertys.Contains(item);
}
public void CopyTo(XuiavrPropertyScriptableObject[] array, int arrayIndex)
{
propertys.CopyTo(array, arrayIndex);
}
public bool Remove(XuiavrPropertyScriptableObject item)
{
return propertys.Remove(item);
}
public int Count => propertys.Count;
public bool IsReadOnly => true;
public int IndexOf(XuiavrPropertyScriptableObject item)
{
return propertys.IndexOf(item);
}
public void Insert(int index, XuiavrPropertyScriptableObject item)
{
propertys.Insert(index, item);
}
public void RemoveAt(int index)
{
propertys.RemoveAt(index);
}
public XuiavrPropertyScriptableObject this[int index]
{
get => propertys[index];
set => propertys[index] = value;
}
}
}
}