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
}
}