using System; using System.Collections.Generic; using System.Reflection; using UnityEngine; using UnityEngine.Pool; namespace XericUI.ReflectionUIGenerator { /// /// UI 字段标记提供者接口 /// 所有 Tag 增强的 UI 组件需实现此接口,便于 Entry 在绑定阶段自动匹配 /// public interface IXuiavrgFieldTagProvider { XuiavrgFieldTag EntryTag { get; } int TagIndex { get; } } /// /// 字段 Entry 接口 /// 数据对象字段与 UI 组件之间的中间缓存层 /// public interface IFieldEntry { /// Entry 名称(字段名或编组路径) string EntryName { get; } /// Entry 完整路径(含父级路径) string EntryPath { get; } /// 主要功能标记 XuiavrgFieldTag Tag { get; } /// 标记索引 int TagIndex { get; } /// 排序值(越小越靠前) int FieldOrder { get; set; } /// 是否为编组 Entry(包含子 Entry) bool IsGroupEntry { get; } /// 父 Entry IFieldEntry Parent { get; } /// 子 Entry 列表(只读) IReadOnlyList Children { get; } /// 生成的 UI 实例引用 GameObject UIInstance { get; } /// 绑定的预制体组 XuiavrgPropertyGroupScriptableObject BoundPrefabGroup { get; set; } /// 覆盖的预制体组名称 string PrefabOverrideName { get; set; } // === 生命周期 === /// Entry 创建时调用 void OnEntryCreate(); /// 绑定 UI 和数据时调用 void OnEntryBind(); /// 释放时调用(归还池前) void OnEntryRelease(); /// 销毁时调用 void OnEntryDestroy(); // === 数据访问 === /// 获取指定成员的数据值 object GetDataValue(string memberName); /// 设置指定成员的数据值 void SetDataValue(string memberName, object value); /// 获取 Entry 下所有绑定成员的名称 IEnumerable GetMemberNames(); // === UI 绑定 === /// /// 绑定 UI 组件 /// /// UI 预制体实例 /// /// 组件缓存列表。传入 null 时会自动收集 uiInstance 上所有 Component。 /// 父 Entry 可将已收集的缓存传递给子 Entry 以提升性能 /// void BindUIComponent(GameObject uiInstance, List componentCache); } /// /// 字段临时 Entry 实现类 /// 作为数据对象字段和 UI 组件之间的中间缓存层 /// /// 支持: /// - 多字段合并为一个 Entry(通过 XuiavrgFieldEntryGroupAttribute) /// - 嵌套 Entry(父 Entry 包含子 Entry) /// - 对象池复用(通过静态 ObjectPool) /// - MVVM 双向绑定的生命周期 /// public class XuiFieldTempEntry : IFieldEntry { #region 对象池 internal static ObjectPool Pool { get; private set; } static XuiFieldTempEntry() { Pool = new ObjectPool( createFunc: () => new XuiFieldTempEntry(), actionOnGet: entry => entry.OnEntryCreate(), actionOnRelease: entry => entry.OnEntryRelease(), actionOnDestroy: entry => entry.OnEntryDestroy(), collectionCheck: false, defaultCapacity: 32, maxSize: 512 ); } /// 从池中获取 Entry 实例 public static XuiFieldTempEntry Get() => Pool.Get(); /// 将 Entry 归还池中 public static void Release(XuiFieldTempEntry entry) => Pool.Release(entry); #endregion #region 内部绑定数据结构 /// /// 成员反射绑定信息 /// internal class MemberBinding { /// 绑定的数据目标对象 public object valueTarget; /// 是否为属性(false 为字段) public bool isProperty; /// 属性信息 public PropertyInfo propertyInfo; /// 字段信息 public FieldInfo fieldInfo; /// 功能标记 public XuiavrgFieldTag tag; /// 标记索引 public int tagIndex; /// /// 从绑定目标获取值 /// public object GetValue() { if (valueTarget == null) return null; return isProperty ? propertyInfo.GetValue(valueTarget) : fieldInfo.GetValue(valueTarget); } /// /// 设置值到绑定目标 /// public void SetValue(object value) { if (valueTarget == null) return; if (isProperty) { if (propertyInfo.CanWrite) propertyInfo.SetValue(valueTarget, value); } else { fieldInfo.SetValue(valueTarget, value); } } } #endregion #region 字段 private string _entryName; private string _entryPath; private IFieldEntry _parent; private List _children = new List(); private Dictionary _bindings = new Dictionary(); private GameObject _uiInstance; private XuiavrgPropertyGroupScriptableObject _boundPrefabGroup; private string _prefabOverrideName; private int _fieldOrder; #endregion #region IFieldEntry 属性实现 public string EntryName => _entryName; public string EntryPath { get { if (!string.IsNullOrEmpty(_entryPath)) return _entryPath; if (_parent != null) { string parentPath = _parent.EntryPath; return string.IsNullOrEmpty(parentPath) ? _entryName : parentPath + "/" + _entryName; } return _entryName; } } public XuiavrgFieldTag Tag { get; private set; } public int TagIndex { get; private set; } public int FieldOrder { get => _fieldOrder; set => _fieldOrder = value; } public bool IsGroupEntry => _children.Count > 0; public IFieldEntry Parent => _parent; public IReadOnlyList Children => _children; public GameObject UIInstance => _uiInstance; public XuiavrgPropertyGroupScriptableObject BoundPrefabGroup { get => _boundPrefabGroup; set => _boundPrefabGroup = value; } public string PrefabOverrideName { get => _prefabOverrideName; set => _prefabOverrideName = value; } #endregion #region 初始化方法 /// /// 设置 Entry 基本属性 /// public void Initialize(string entryName, XuiavrgFieldTag tag = XuiavrgFieldTag.None, int tagIndex = 0) { _entryName = entryName; _entryPath = null; Tag = tag; TagIndex = tagIndex; _fieldOrder = 0; } /// /// 设置父 Entry(用于嵌套) /// public void SetParent(IFieldEntry parent) { _parent = parent; _entryPath = null; // 重置路径,下次访问重新计算 } /// /// 添加子 Entry /// public void AddChild(XuiFieldTempEntry child) { if (child == null) return; child.SetParent(this); _children.Add(child); } /// /// 注册成员绑定 /// /// 成员名称 /// 反射信息 /// 数据目标对象 /// 功能标记 /// 标记索引 public void RegisterBinding(string memberName, MemberInfo memberInfo, object target, XuiavrgFieldTag tag = XuiavrgFieldTag.None, int tagIndex = 0) { MemberBinding binding = new MemberBinding { valueTarget = target, tag = tag, tagIndex = tagIndex }; switch (memberInfo) { case PropertyInfo propInfo: binding.isProperty = true; binding.propertyInfo = propInfo; break; case FieldInfo fieldInfo: binding.isProperty = false; binding.fieldInfo = fieldInfo; break; } _bindings[memberName] = binding; // 如果是第一个注册的绑定,设置主 Tag if (Tag == XuiavrgFieldTag.None && tag != XuiavrgFieldTag.None) { Tag = tag; TagIndex = tagIndex; } } #endregion #region 数据访问 public object GetDataValue(string memberName) { if (_bindings.TryGetValue(memberName, out var binding)) return binding.GetValue(); // 查找子 Entry foreach (var child in _children) { var value = child.GetDataValue(memberName); if (value != null) return value; } return null; } public void SetDataValue(string memberName, object value) { if (_bindings.TryGetValue(memberName, out var binding)) { binding.SetValue(value); return; } // 查找子 Entry foreach (var child in _children) { if (child.HasBinding(memberName)) { child.SetDataValue(memberName, value); return; } } } public IEnumerable GetMemberNames() => _bindings.Keys; /// /// 检查是否包含指定成员绑定 /// public bool HasBinding(string memberName) => _bindings.ContainsKey(memberName); /// /// 获取指定成员的标记 /// public XuiavrgFieldTag GetMemberTag(string memberName) { if (_bindings.TryGetValue(memberName, out var binding)) return binding.tag; return XuiavrgFieldTag.None; } #endregion #region UI 绑定 public void BindUIComponent(GameObject uiInstance, List componentCache) { _uiInstance = uiInstance; if (_uiInstance == null) return; if (componentCache == null) { componentCache = new List(); _uiInstance.GetComponentsInChildren(true, componentCache); } BindUIComponentWithCache(_uiInstance, componentCache); // 子 Entry 复用组件缓存 foreach (var child in _children) { child.BindUIComponent(_uiInstance, componentCache); } } private void BindUIComponentWithCache(GameObject uiInstance, List componentCache) { // 遍历组件缓存,匹配 tag var locators = new List(); foreach (var comp in componentCache) { if (comp is XuiavrgLocator locator) { locators.Add(locator); } if (comp is IXuiavrgFieldTagProvider tagProvider) { // 匹配 Tag 和 TagIndex if (tagProvider.EntryTag == this.Tag && (this.TagIndex == 0 || tagProvider.TagIndex == this.TagIndex)) { // 找到匹配的 UI 组件,建立绑定 BuildComponentBinding(comp); } } } // 如果没有 IXuiavrgFieldTagProvider,尝试通过 Locator 匹配 if (locators.Count > 0) { BuildLocatorBindings(locators); } } /// /// 通过标签提供者建立组件绑定 /// private void BuildComponentBinding(Component comp) { // 根据组件类型和标记类型进行数据同步 switch (comp) { case UnityEngine.UI.Text uiText when Tag == XuiavrgFieldTag.Label || Tag == XuiavrgFieldTag.Output: uiText.text = GetFirstBindingValue()?.ToString() ?? ""; break; case UnityEngine.UI.Button _ when Tag == XuiavrgFieldTag.Button: // 按钮绑定在 BindUIEvents 中处理 break; case UnityEngine.UI.Toggle uiToggle when Tag == XuiavrgFieldTag.Toggle: if (GetFirstBindingValue() is bool boolVal) uiToggle.isOn = boolVal; break; case UnityEngine.UI.Slider uiSlider when Tag == XuiavrgFieldTag.Slider: if (GetFirstBindingValue() is float floatVal) uiSlider.value = floatVal; break; case UnityEngine.UI.InputField uiInput when Tag == XuiavrgFieldTag.Input: uiInput.text = GetFirstBindingValue()?.ToString() ?? ""; break; case UnityEngine.UI.Dropdown uiDropdown when Tag == XuiavrgFieldTag.Dropdown: if (GetFirstBindingValue() is int intVal) uiDropdown.value = intVal; break; } } /// /// 通过 Locator 建立绑定 /// private void BuildLocatorBindings(List locators) { foreach (var locator in locators) { foreach (var locProp in locator.Properties) { // 按 propertyName 匹配成员名 if (_bindings.TryGetValue(locProp.propertyName, out var binding)) { // 从数据端同步到 UI var dataValue = binding.GetValue(); locProp.SetValue(dataValue); } } } } /// /// 获取第一个绑定的值 /// private object GetFirstBindingValue() { foreach (var kvp in _bindings) { var val = kvp.Value.GetValue(); if (val != null) return val; } return null; } #endregion #region 事件绑定 /// /// 绑定 UI 交互事件(双向绑定) /// public void BindUIEvents() { if (_uiInstance == null) return; var allComponents = new List(); _uiInstance.GetComponentsInChildren(true, allComponents); foreach (var comp in allComponents) { if (comp is IXuiavrgFieldTagProvider tagProvider) { if (tagProvider.EntryTag != this.Tag) continue; BindComponentEvents(comp); } } // 子 Entry 事件绑定 foreach (var child in _children) { child.BindUIEvents(); } } private void BindComponentEvents(Component comp) { switch (comp) { case UnityEngine.UI.Button uiButton: uiButton.onClick.AddListener(() => { SetFirstBindingValue(true); }); break; case UnityEngine.UI.Toggle uiToggle: uiToggle.onValueChanged.AddListener(val => { SetFirstBindingValue(val); }); break; case UnityEngine.UI.Slider uiSlider: uiSlider.onValueChanged.AddListener(val => { SetFirstBindingValue(val); }); break; case UnityEngine.UI.InputField uiInput: uiInput.onEndEdit.AddListener(val => { SetFirstBindingValue(val); }); break; case UnityEngine.UI.Dropdown uiDropdown: uiDropdown.onValueChanged.AddListener(val => { SetFirstBindingValue(val); }); break; } } private void SetFirstBindingValue(object value) { foreach (var kvp in _bindings) { kvp.Value.SetValue(value); break; } } #endregion #region 生命周期 public void OnEntryCreate() { _entryName = null; _entryPath = null; _parent = null; _fieldOrder = 0; _prefabOverrideName = null; } public void OnEntryBind() { BindUIEvents(); } public void OnEntryRelease() { _entryName = null; _entryPath = null; _parent = null; _uiInstance = null; _boundPrefabGroup = null; _prefabOverrideName = null; Tag = XuiavrgFieldTag.None; TagIndex = 0; _fieldOrder = 0; // 清理绑定引用 _bindings.Clear(); // 递归释放子 Entry foreach (var child in _children) { Release(child); } _children.Clear(); } public void OnEntryDestroy() { _bindings.Clear(); _children.Clear(); _uiInstance = null; } #endregion } }