diff --git a/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsAttribute.cs b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsAttribute.cs new file mode 100644 index 0000000..9b13dc6 --- /dev/null +++ b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsAttribute.cs @@ -0,0 +1,33 @@ +using System; + +namespace XericUI.ReflectionUIGenerator +{ + /// + /// 专用 UI 特性抽象基类 + /// 每个 UI 组件类型(Dropdown/Slider/InputField/Button)都有自己的专用 Attribute, + /// 继承此类即可自动设置 Tag 并携带 UI 相关配置。 + /// + /// UI 侧查询方式:metaData.Attributes.OfType() 获取专用配置 + /// + /// 使用示例: + /// [XuiavrgFieldAsDropdown("选项A", "选项B", "选项C")] + /// public float myOption; + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)] + public abstract class XuiavrgFieldAsAttribute : Attribute, IXuiavrgAttribute + { + /// 子类指定自己的功能标记 + public abstract XuiavrgFieldTag TargetTag { get; } + + /// + /// 绑定元数据:自动设置 Tag + /// 子类重写此方法时应在开头调用 base.BindMetaData(metaData) + /// + public virtual void BindMetaData(AvrgMemberMetaData metaData) + { + metaData.Tag = TargetTag; + // 专用特性自动被收集到 metaData.Attributes 中 + // UI 侧通过 metaData.Attributes.OfType() 查询配置 + } + } +} diff --git a/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsAttribute.cs.meta b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsAttribute.cs.meta new file mode 100644 index 0000000..3b7f3d0 --- /dev/null +++ b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d04aeafdc2894de4ca7f573edd3ed355 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsButtonAttribute.cs b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsButtonAttribute.cs new file mode 100644 index 0000000..4bad0f4 --- /dev/null +++ b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsButtonAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace XericUI.ReflectionUIGenerator +{ + /// + /// 字段作为按钮(Button)的专用特性 + /// 自动设置 Tag = Button,无额外配置参数 + /// + /// 使用示例: + /// [XuiavrgFieldAsButton] + /// public bool trigger; + /// + public class XuiavrgFieldAsButtonAttribute : XuiavrgFieldAsAttribute + { + public override XuiavrgFieldTag TargetTag => XuiavrgFieldTag.Button; + } +} diff --git a/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsButtonAttribute.cs.meta b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsButtonAttribute.cs.meta new file mode 100644 index 0000000..377f2a6 --- /dev/null +++ b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsButtonAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 311c35776d5a75b4696124d13680aa67 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsDropdownAttribute.cs b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsDropdownAttribute.cs new file mode 100644 index 0000000..702c30e --- /dev/null +++ b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsDropdownAttribute.cs @@ -0,0 +1,36 @@ +using System; + +namespace XericUI.ReflectionUIGenerator +{ + /// + /// 字段作为下拉框(Dropdown)的专用特性 + /// 自动设置 Tag = Dropdown,并携带默认选项列表 + /// + /// 使用示例: + /// [XuiavrgFieldAsDropdown("选项A", "选项B", "选项C")] + /// public float mode; + /// + /// [XuiavrgFieldAsDropdown(1, 2, 3)] // 也支持数字 + /// public int intMode; + /// + /// UI 侧查询方式: + /// metaData.Attributes.OfType() + /// .FirstOrDefault()?.DefaultValues + /// + public class XuiavrgFieldAsDropdownAttribute : XuiavrgFieldAsAttribute + { + /// 默认选项列表 + public object[] DefaultValues { get; } + + public override XuiavrgFieldTag TargetTag => XuiavrgFieldTag.Dropdown; + + /// + /// 创建下拉框专用特性 + /// + /// 默认选项值列表(params 参数,支持任意编译期常量类型) + public XuiavrgFieldAsDropdownAttribute(params object[] defaultValues) + { + DefaultValues = defaultValues ?? Array.Empty(); + } + } +} diff --git a/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsDropdownAttribute.cs.meta b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsDropdownAttribute.cs.meta new file mode 100644 index 0000000..3a66fe2 --- /dev/null +++ b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsDropdownAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 755f4db45daa6b94fb63e289b1d3c5b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsInputFieldAttribute.cs b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsInputFieldAttribute.cs new file mode 100644 index 0000000..62f1a5f --- /dev/null +++ b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsInputFieldAttribute.cs @@ -0,0 +1,36 @@ +using System; + +namespace XericUI.ReflectionUIGenerator +{ + /// + /// 字段作为输入框(InputField)的专用特性 + /// 自动设置 Tag = Input,并携带占位文本 + /// + /// 使用示例: + /// [XuiavrgFieldAsInputField("请输入名称")] + /// public string name; + /// + /// [XuiavrgFieldAsInputField("输入数字")] + /// public float score; + /// + /// UI 侧查询方式: + /// metaData.Attributes.OfType() + /// .FirstOrDefault()?.PlaceholderText + /// + public class XuiavrgFieldAsInputFieldAttribute : XuiavrgFieldAsAttribute + { + /// 输入框占位文本(无输入时显示的灰色提示) + public string PlaceholderText { get; } + + public override XuiavrgFieldTag TargetTag => XuiavrgFieldTag.Input; + + /// + /// 创建输入框专用特性 + /// + /// 占位文本(无输入时的提示) + public XuiavrgFieldAsInputFieldAttribute(string placeholderText) + { + PlaceholderText = placeholderText ?? ""; + } + } +} diff --git a/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsInputFieldAttribute.cs.meta b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsInputFieldAttribute.cs.meta new file mode 100644 index 0000000..436fd6c --- /dev/null +++ b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsInputFieldAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 827b86614f1b91f46948f54a7c5b5e1b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsSliderAttribute.cs b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsSliderAttribute.cs new file mode 100644 index 0000000..46e93f3 --- /dev/null +++ b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsSliderAttribute.cs @@ -0,0 +1,41 @@ +using System; + +namespace XericUI.ReflectionUIGenerator +{ + /// + /// 字段作为滑动条(Slider)的专用特性 + /// 自动设置 Tag = Slider,并携带最小值和最大值 + /// + /// 使用示例: + /// [XuiavrgFieldAsSlider(-100f, 100f)] + /// public float speed; + /// + /// 对于 Vector2 类型(范围滑块),UI 端可通过 ValueType 判断切换 MinMax 模式, + /// 此时 Slider 的 Min/Max 作为边界值 + /// + /// UI 侧查询方式: + /// metaData.Attributes.OfType() + /// .FirstOrDefault() + /// + public class XuiavrgFieldAsSliderAttribute : XuiavrgFieldAsAttribute + { + /// 滑动条最小值 + public float MinValue { get; } + + /// 滑动条最大值 + public float MaxValue { get; } + + public override XuiavrgFieldTag TargetTag => XuiavrgFieldTag.Slider; + + /// + /// 创建滑动条专用特性 + /// + /// 最小值 + /// 最大值 + public XuiavrgFieldAsSliderAttribute(float min, float max) + { + MinValue = min; + MaxValue = max; + } + } +} diff --git a/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsSliderAttribute.cs.meta b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsSliderAttribute.cs.meta new file mode 100644 index 0000000..c78131a --- /dev/null +++ b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/Attribute/XuiavrgFieldAsSliderAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 15359a75f4e32f44e87a56b9980a3fcc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/InterfaceAttributeReflectionGenerator/Scripts/AvrgMemberMetaDataSet.cs b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/AvrgMemberMetaDataSet.cs index 8e174ae..b2810c2 100644 --- a/Runtime/InterfaceAttributeReflectionGenerator/Scripts/AvrgMemberMetaDataSet.cs +++ b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/AvrgMemberMetaDataSet.cs @@ -49,15 +49,18 @@ namespace XericUI.ReflectionUIGenerator { // 编组内第一个成员作为主元数据 var first = gEntry.First(); - // 收集组内所有成员的 SubMetaDataList(合并拆分属性) + first.SubMetaDataList ??= new List(); + foreach (var member in gEntry) { + if (member == first) continue; + + // 成员自身的 Split 子属性合并到父级 if (member.SubMetaDataList?.Count > 0) - { - if (first.SubMetaDataList == null) - first.SubMetaDataList = new List(); first.SubMetaDataList.AddRange(member.SubMetaDataList); - } + + // Merge: 成员自身作为子属性加入,保留独立 MemberInfo/TargetInstance + first.SubMetaDataList.Add(member); } merged.Add(first); } @@ -122,23 +125,39 @@ namespace XericUI.ReflectionUIGenerator foreach (var subMetaData in metaData.SubMetaDataList) { - string subPath = subMetaData.PropertyPath; - if (string.IsNullOrEmpty(subPath)) continue; - var subBinding = new AvrgMvvmBinding { MetaData = subMetaData, - // 从父值中读取子属性 - ReadFunc = () => ReadSubProperty(metaData.GetValue(), subPath), - // 修改子属性并写回父值 - WriteAction = (val) => + }; + + // Merge 路径:子字段有自己的 MemberInfo/TargetInstance(来自编组成员) + if (subMetaData.MemberInfo != null && subMetaData.TargetInstance != null) + { + var capturedSub = subMetaData; + subBinding.ReadFunc = () => capturedSub.GetValue(); + subBinding.WriteAction = (val) => + { + capturedSub.SetValue(val); + scheduler.MarkDataDirty(capturedBinding); + }; + } + // Split 路径:通过 PropertyPath 从父值访问(来自 XuiavrgSplit) + else if (!string.IsNullOrEmpty(subMetaData.PropertyPath)) + { + string subPath = subMetaData.PropertyPath; + subBinding.ReadFunc = () => ReadSubProperty(metaData.GetValue(), subPath); + subBinding.WriteAction = (val) => { var parentVal = metaData.GetValue(); var modifiedParent = WriteSubProperty(parentVal, subPath, val); metaData.SetValue(modifiedParent); scheduler.MarkDataDirty(capturedBinding); - }, - }; + }; + } + else + { + continue; // 无法创建绑定,跳过 + } binding.SubBindings.Add(subBinding); }