From fe5ae4726cf4a8d78b0dc0db6ba50d63dfb9c232 Mon Sep 17 00:00:00 2001
From: lrc <571244399@qq.com>
Date: Sat, 25 Jul 2026 23:56:29 +0800
Subject: [PATCH] =?UTF-8?q?=E6=94=B6=E7=B4=A7=E5=90=84=E7=BB=84=E4=BB=B6?=
=?UTF-8?q?=E6=9D=83=E9=99=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Scripts/AvrgBindingTrie.cs.meta | 11 ++
.../Scripts/AvrgSubPropertyAccessor.cs.meta | 11 ++
.../Scripts/ValidationState.cs.meta | 11 ++
.../AvrgValues/XUIAvrgMDDropdownValue.cs | 49 ++++++-
.../AvrgValues/XUIAvrgMDLabelValue.cs | 44 +++++-
.../AvrgValues/XUIAvrgMDSliderValue.cs | 90 +++++++++---
.../AvrgValues/XUIAvrgMDToggleGroupValue.cs | 136 ++++++++++++++----
.../OverrideUI/AvrgValues/XUIAvrgMDValue.cs | 85 ++++++-----
8 files changed, 342 insertions(+), 95 deletions(-)
create mode 100644 Runtime/InterfaceAttributeReflectionGenerator/Scripts/AvrgBindingTrie.cs.meta
create mode 100644 Runtime/InterfaceAttributeReflectionGenerator/Scripts/AvrgSubPropertyAccessor.cs.meta
create mode 100644 Runtime/InterfaceAttributeReflectionGenerator/Scripts/ValidationState.cs.meta
diff --git a/Runtime/InterfaceAttributeReflectionGenerator/Scripts/AvrgBindingTrie.cs.meta b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/AvrgBindingTrie.cs.meta
new file mode 100644
index 0000000..fe68f26
--- /dev/null
+++ b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/AvrgBindingTrie.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0fbb9c5ea2b8b5644a49559e7b6260e0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/InterfaceAttributeReflectionGenerator/Scripts/AvrgSubPropertyAccessor.cs.meta b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/AvrgSubPropertyAccessor.cs.meta
new file mode 100644
index 0000000..70496d4
--- /dev/null
+++ b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/AvrgSubPropertyAccessor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c0ab49f7e492a8d448cdcc9f214325f6
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/InterfaceAttributeReflectionGenerator/Scripts/ValidationState.cs.meta b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/ValidationState.cs.meta
new file mode 100644
index 0000000..eb94e88
--- /dev/null
+++ b/Runtime/InterfaceAttributeReflectionGenerator/Scripts/ValidationState.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e20b793a32d670a4d95e20189dd27694
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/OverrideUI/AvrgValues/XUIAvrgMDDropdownValue.cs b/Runtime/OverrideUI/AvrgValues/XUIAvrgMDDropdownValue.cs
index 20dbdb9..05344ef 100644
--- a/Runtime/OverrideUI/AvrgValues/XUIAvrgMDDropdownValue.cs
+++ b/Runtime/OverrideUI/AvrgValues/XUIAvrgMDDropdownValue.cs
@@ -8,18 +8,24 @@ namespace XericUI.ReflectionUIGenerator
///
/// Dropdown 值组件 — 处理 string / int / enum 类型的下拉选择交互
/// 预设选项来源:元数据的 PresetOptions 或 enum 类型的枚举名
+ ///
+ /// 选项动态创建:OnPoolGet 时根据元数据 PresetOptions 构建选项列表,
+ /// BindToAccessor 时通过 AddOptions() 填充到 Dropdown 组件。
///
[AddComponentMenu("Xeric Library/UI Action Vessel/Values/XUIAvrgMDDropdownValue")]
public class XUIAvrgMDDropdownValue : XUIAvrgMDValue
{
- [SerializeField]
- [Tooltip("关联的 Dropdown 组件(未设置则自动查找)")]
+ [SerializeField, Tooltip("关联的 Dropdown 组件(未设置则自动查找)")]
#if dUI_TextMeshPro
private TMPro.TMP_Dropdown _dropdown;
#else
private Dropdown _dropdown;
#endif
+ [Header("选项动态创建")]
+ [SerializeField, Tooltip("选项项预制体 Transform(可选,用于自定义选项创建逻辑)")]
+ private Transform _optionItemPrefab;
+
private List _options;
private void Awake()
@@ -37,16 +43,55 @@ namespace XericUI.ReflectionUIGenerator
{
base.OnPoolGet(metaData);
_options = BuildOptions(metaData?.ValueType);
+
+ // 动态创建选项对象(子类可覆写)
+ CreateOptionItems();
}
public override void OnPoolRelease()
{
if (_dropdown != null)
_dropdown.onValueChanged.RemoveAllListeners();
+
+ DestroyOptionItems();
_options = null;
base.OnPoolRelease();
}
+ // ============ 动态选项创建 ============
+
+ ///
+ /// 根据预设选项动态创建选项子对象
+ /// 子类可覆写以实现自定义选项创建(如图标、颜色等)
+ ///
+ protected virtual void CreateOptionItems()
+ {
+ if (_optionItemPrefab == null || _options == null) return;
+
+ for (int i = 0; i < _options.Count; i++)
+ {
+ var item = Instantiate(_optionItemPrefab, _optionItemPrefab.parent);
+ item.name = $"Option_{i}_{_options[i]}";
+ item.gameObject.SetActive(true);
+ }
+ }
+
+ ///
+ /// 销毁动态创建的选项子对象
+ ///
+ protected virtual void DestroyOptionItems()
+ {
+ if (_optionItemPrefab == null) return;
+
+ var parent = _optionItemPrefab.parent;
+ for (int i = parent.childCount - 1; i >= 0; i--)
+ {
+ var child = parent.GetChild(i);
+ if (child != _optionItemPrefab)
+ Destroy(child.gameObject);
+ }
+ }
+
// ============ 核心绑定 ============
public override void BindToAccessor(
diff --git a/Runtime/OverrideUI/AvrgValues/XUIAvrgMDLabelValue.cs b/Runtime/OverrideUI/AvrgValues/XUIAvrgMDLabelValue.cs
index 85c63b7..46e3a9d 100644
--- a/Runtime/OverrideUI/AvrgValues/XUIAvrgMDLabelValue.cs
+++ b/Runtime/OverrideUI/AvrgValues/XUIAvrgMDLabelValue.cs
@@ -1,19 +1,27 @@
using UnityEngine;
-using UnityEngine.UI;
namespace XericUI.ReflectionUIGenerator
{
///
/// Label 只读值组件 — 纯文本展示,无交互控件
+ /// 拥有自己的 _valueDisplayText 用于显示值
///
[AddComponentMenu("Xeric Library/UI Action Vessel/Values/XUIAvrgMDLabelValue")]
public class XUIAvrgMDLabelValue : XUIAvrgMDValue
{
+ [SerializeField, Tooltip("值显示文本 — 显示当前字段的值")]
#if dUI_TextMeshPro
- [SerializeField, Tooltip("关联的 TMP_Text 组件(标签文本 + 值文本共用一个 Text 时使用)")]
- private TMPro.TMP_Text _tmpText;
+ private TMPro.TMP_Text _valueDisplayText;
+#else
+ private UnityEngine.UI.Text _valueDisplayText;
#endif
+ public override void OnPoolRelease()
+ {
+ if (_valueDisplayText != null) _valueDisplayText.text = "";
+ base.OnPoolRelease();
+ }
+
public override void BindToAccessor(
IAvrgValueAccessor accessor,
AvrgMvvmBinding binding,
@@ -33,5 +41,35 @@ namespace XericUI.ReflectionUIGenerator
var initialValue = accessor.GetValue();
UpdateValueDisplay(initialValue, ValidationState.Normal);
}
+
+ protected override void UpdateValueDisplay(object value, ValidationState state)
+ {
+ if (_valueDisplayText != null)
+ {
+ _valueDisplayText.text = CurrentAccessor?.FormatDisplay(value) ?? value?.ToString() ?? "";
+
+ _valueDisplayText.color = state == ValidationState.Invalid
+ ? Color.red
+ : state == ValidationState.Warning
+ ? new Color(1f, 0.92f, 0.016f)
+ : Color.white;
+ }
+
+ base.UpdateValueDisplay(value, state);
+ }
+
+ protected override void OnValidationStateChanged(ValidationState state)
+ {
+ base.OnValidationStateChanged(state);
+
+ if (_valueDisplayText != null)
+ {
+ _valueDisplayText.color = state == ValidationState.Invalid
+ ? Color.red
+ : state == ValidationState.Warning
+ ? new Color(1f, 0.92f, 0.016f)
+ : Color.white;
+ }
+ }
}
}
diff --git a/Runtime/OverrideUI/AvrgValues/XUIAvrgMDSliderValue.cs b/Runtime/OverrideUI/AvrgValues/XUIAvrgMDSliderValue.cs
index 5f3f6d5..ab48756 100644
--- a/Runtime/OverrideUI/AvrgValues/XUIAvrgMDSliderValue.cs
+++ b/Runtime/OverrideUI/AvrgValues/XUIAvrgMDSliderValue.cs
@@ -15,17 +15,33 @@ namespace XericUI.ReflectionUIGenerator
private Slider _slider;
[Header("Slider 专属插槽")]
+ [SerializeField, Tooltip("值显示文本 — 显示当前 Slider 数值")]
+#if dUI_TextMeshPro
+ private TMPro.TMP_Text _valueDisplayText;
+#else
+ private UnityEngine.UI.Text _valueDisplayText;
+#endif
+
+ [SerializeField, Tooltip("最小值文本 — 显示 Slider 下限")]
+#if dUI_TextMeshPro
+ private TMPro.TMP_Text _minValueText;
+#else
+ private UnityEngine.UI.Text _minValueText;
+#endif
+
+ [SerializeField, Tooltip("最大值文本 — 显示 Slider 上限")]
+#if dUI_TextMeshPro
+ private TMPro.TMP_Text _maxValueText;
+#else
+ private UnityEngine.UI.Text _maxValueText;
+#endif
+
[SerializeField, Tooltip("增加按钮(点击按步进值 +)")]
private Button _incrementButton;
[SerializeField, Tooltip("减少按钮(点击按步进值 -)")]
private Button _decrementButton;
-#if dUI_TextMeshPro
- [SerializeField, Tooltip("值显示标签(可选,未设置则不更新)")]
- private TMPro.TMP_Text _valueLabel;
-#endif
-
private const float DefaultStep = 0.1f;
private void Awake()
@@ -51,7 +67,6 @@ namespace XericUI.ReflectionUIGenerator
public override void OnPoolRelease()
{
- // 清除按钮监听
if (_incrementButton != null)
_incrementButton.onClick.RemoveAllListeners();
if (_decrementButton != null)
@@ -59,6 +74,11 @@ namespace XericUI.ReflectionUIGenerator
if (_slider != null)
_slider.onValueChanged.RemoveAllListeners();
+ // 重置子类文本
+ if (_valueDisplayText != null) _valueDisplayText.text = "";
+ if (_minValueText != null) _minValueText.text = "";
+ if (_maxValueText != null) _maxValueText.text = "";
+
base.OnPoolRelease();
}
@@ -74,6 +94,9 @@ namespace XericUI.ReflectionUIGenerator
if (binding == null || accessor == null || _slider == null) return;
+ // 初始化上下限文本
+ ApplyRangeTexts();
+
// 增减按钮
if (_incrementButton != null)
_incrementButton.onClick.AddListener(OnIncrementClicked);
@@ -87,10 +110,7 @@ namespace XericUI.ReflectionUIGenerator
binding.WriteFromUI(convertedVal);
scheduler?.MarkUIDirty(binding);
-#if dUI_TextMeshPro
- if (_valueLabel != null)
- _valueLabel.text = accessor.FormatDisplay(convertedVal);
-#endif
+ RefreshValueText(convertedVal);
});
// 数据 → UI(带验证状态)
@@ -99,12 +119,9 @@ namespace XericUI.ReflectionUIGenerator
float sliderVal = Convert.ToSingle(value);
_slider.SetValueWithoutNotify(sliderVal);
-#if dUI_TextMeshPro
- if (_valueLabel != null)
- _valueLabel.text = accessor.FormatDisplay(value);
-#endif
+ RefreshValueText(value);
+ ApplyValueTextColor(state);
- // 委托基类处理标签合成 + 值文本
base.UpdateValueDisplay(value, state);
};
@@ -114,16 +131,45 @@ namespace XericUI.ReflectionUIGenerator
// 首次同步
var initialValue = accessor.GetValue();
if (initialValue != null)
- {
_slider.SetValueWithoutNotify(Convert.ToSingle(initialValue));
-#if dUI_TextMeshPro
- if (_valueLabel != null)
- _valueLabel.text = accessor.FormatDisplay(initialValue);
-#endif
- }
+
+ RefreshValueText(initialValue);
UpdateValueDisplay(initialValue ?? 0f, ValidationState.Normal);
}
+ // ============ 值显示 ============
+
+ protected override void UpdateValueDisplay(object value, ValidationState state)
+ {
+ ApplyValueTextColor(state);
+ base.UpdateValueDisplay(value, state);
+ }
+
+ private void RefreshValueText(object value)
+ {
+ if (_valueDisplayText == null || CurrentAccessor == null) return;
+ _valueDisplayText.text = CurrentAccessor.FormatDisplay(value);
+ }
+
+ private void ApplyValueTextColor(ValidationState state)
+ {
+ if (_valueDisplayText == null) return;
+
+ _valueDisplayText.color = state == ValidationState.Invalid
+ ? Color.red
+ : state == ValidationState.Warning
+ ? new Color(1f, 0.92f, 0.016f)
+ : Color.white;
+ }
+
+ private void ApplyRangeTexts()
+ {
+ if (_minValueText != null)
+ _minValueText.text = CurrentAccessor?.FormatDisplay(_slider.minValue) ?? _slider.minValue.ToString();
+ if (_maxValueText != null)
+ _maxValueText.text = CurrentAccessor?.FormatDisplay(_slider.maxValue) ?? _slider.maxValue.ToString();
+ }
+
// ============ 步进值 ============
private float GetStepValue()
@@ -169,6 +215,8 @@ namespace XericUI.ReflectionUIGenerator
};
}
}
+
+ ApplyValueTextColor(state);
}
private static object ConvertValueForAccessor(float val, Type targetType)
diff --git a/Runtime/OverrideUI/AvrgValues/XUIAvrgMDToggleGroupValue.cs b/Runtime/OverrideUI/AvrgValues/XUIAvrgMDToggleGroupValue.cs
index 9c4ff8a..e19078e 100644
--- a/Runtime/OverrideUI/AvrgValues/XUIAvrgMDToggleGroupValue.cs
+++ b/Runtime/OverrideUI/AvrgValues/XUIAvrgMDToggleGroupValue.cs
@@ -8,26 +8,125 @@ namespace XericUI.ReflectionUIGenerator
///
/// ToggleGroup 值组件 — 处理 string / int / enum 类型的单选组交互
/// 适用于标记了 [XuiavrgFieldToggleGroupValue] 的字段
+ ///
+ /// 选项动态创建:OnPoolGet 时根据元数据 PresetOptions 数量,
+ /// 从 _toggleItemPrefab 实例化 Toggle 子对象。
///
[AddComponentMenu("Xeric Library/UI Action Vessel/Values/XUIAvrgMDToggleGroupValue")]
public class XUIAvrgMDToggleGroupValue : XUIAvrgMDValue
{
- [SerializeField]
- [Tooltip("关联的 ToggleGroup 组件(未设置则自动查找)")]
+ [SerializeField, Tooltip("关联的 ToggleGroup 组件(未设置则自动查找)")]
private ToggleGroup _toggleGroup;
+ [Header("选项动态创建")]
+ [SerializeField, Tooltip("Toggle 项预制体 — 在 OnPoolGet 时按预设选项数量实例化")]
+ private Transform _toggleItemPrefab;
+
+ [SerializeField, Tooltip("选项容器 Transform — 动态创建的 Toggle 挂载到此节点下")]
+ private Transform _optionsContainer;
+
private List _toggles = new List();
private List _optionLabels = new List();
private void Awake()
{
if (_toggleGroup == null) _toggleGroup = GetComponent();
- if (_toggleGroup != null)
+ }
+
+ // ============ 对象池生命周期 ============
+
+ public override void OnPoolGet(AvrgMemberMetaData metaData)
+ {
+ base.OnPoolGet(metaData);
+
+ // 构建选项列表
+ BuildOptions(metaData?.ValueType);
+
+ // 动态创建 Toggle 项
+ CreateToggleItems();
+ }
+
+ public override void OnPoolRelease()
+ {
+ // 清理动态创建的 Toggle
+ foreach (var toggle in _toggles)
{
- _toggles = _toggleGroup.GetComponentsInChildren(true).ToList();
+ if (toggle != null)
+ toggle.onValueChanged.RemoveAllListeners();
+ }
+ DestroyToggleItems();
+
+ _toggles.Clear();
+ _optionLabels.Clear();
+
+ base.OnPoolRelease();
+ }
+
+ // ============ 动态 Toggle 创建 ============
+
+ ///
+ /// 根据 _optionLabels 数量,从 _toggleItemPrefab 实例化 Toggle 子对象
+ ///
+ private void CreateToggleItems()
+ {
+ var parent = _optionsContainer != null ? _optionsContainer : transform;
+ if (_toggleItemPrefab == null || _optionLabels.Count == 0) return;
+
+ for (int i = 0; i < _optionLabels.Count; i++)
+ {
+ var item = Instantiate(_toggleItemPrefab, parent);
+ item.name = $"Toggle_{i}_{_optionLabels[i]}";
+ item.gameObject.SetActive(true);
+
+ var toggle = item.GetComponent();
+ if (toggle != null)
+ {
+ toggle.group = _toggleGroup;
+ _toggles.Add(toggle);
+
+ // 设置标签文本
+ var label = item.GetComponentInChildren(true);
+ if (label != null)
+ label.text = _optionLabels[i];
+ }
}
}
+ ///
+ /// 销毁动态创建的所有 Toggle 子对象
+ ///
+ private void DestroyToggleItems()
+ {
+ var parent = _optionsContainer != null ? _optionsContainer : transform;
+
+ foreach (var toggle in _toggles)
+ {
+ if (toggle != null)
+ Destroy(toggle.gameObject);
+ }
+ }
+
+ private void BuildOptions(System.Type valueType)
+ {
+ _optionLabels.Clear();
+
+ // 1. 从元数据 PresetOptions
+ if (BoundMetaData?.PresetOptions != null && BoundMetaData.PresetOptions.Count > 0)
+ {
+ _optionLabels.AddRange(BoundMetaData.PresetOptions);
+ return;
+ }
+
+ // 2. enum 类型
+ if (valueType != null && valueType.IsEnum)
+ {
+ _optionLabels.AddRange(System.Enum.GetNames(valueType));
+ return;
+ }
+ }
+
+ // ============ 核心绑定 ============
+
public override void BindToAccessor(
IAvrgValueAccessor accessor,
AvrgMvvmBinding binding,
@@ -36,10 +135,14 @@ namespace XericUI.ReflectionUIGenerator
CurrentAccessor = accessor;
CurrentBinding = binding;
- if (binding == null || accessor == null || _toggleGroup == null) return;
+ if (binding == null || accessor == null || _toggleGroup == null || _toggles.Count == 0) return;
- // 构建选项
- BuildOptions(accessor.ValueType);
+ // 只读模式下禁用所有 Toggle
+ if (accessor.IsReadOnly)
+ {
+ foreach (var t in _toggles)
+ t.interactable = false;
+ }
// 为每个 Toggle 注册事件
for (int i = 0; i < _toggles.Count && i < _optionLabels.Count; i++)
@@ -88,25 +191,6 @@ namespace XericUI.ReflectionUIGenerator
}
}
- private void BuildOptions(System.Type valueType)
- {
- _optionLabels.Clear();
-
- // 1. 从元数据 PresetOptions
- if (BoundMetaData?.PresetOptions != null && BoundMetaData.PresetOptions.Count > 0)
- {
- _optionLabels.AddRange(BoundMetaData.PresetOptions);
- return;
- }
-
- // 2. enum 类型
- if (valueType != null && valueType.IsEnum)
- {
- _optionLabels.AddRange(System.Enum.GetNames(valueType));
- return;
- }
- }
-
private static object ConvertOptionToValue(string option, System.Type targetType)
{
if (targetType == typeof(string)) return option;
diff --git a/Runtime/OverrideUI/AvrgValues/XUIAvrgMDValue.cs b/Runtime/OverrideUI/AvrgValues/XUIAvrgMDValue.cs
index 9ddee2a..f8cc5c9 100644
--- a/Runtime/OverrideUI/AvrgValues/XUIAvrgMDValue.cs
+++ b/Runtime/OverrideUI/AvrgValues/XUIAvrgMDValue.cs
@@ -13,7 +13,8 @@ namespace XericUI.ReflectionUIGenerator
/// 3. 通过 virtual BindToAccessor() 让子类自行管理 UI 交互事件
/// 4. 对象池生命周期:OnPoolGet(meta) 初始化、OnPoolRelease() 重置
/// 5. 定义绑定槽(BindingSlots),供拆分属性子绑定匹配
- /// 6. 通过 UpdateValueDisplay() 合成标签文本(名称 + 只读 + 警告标记)
+ /// 6. 基类统一管理标签文本(名称 + 只读 + 警告标记)和单位可见性
+ /// 值显示由各子类自行实现
///
[AddComponentMenu("Xeric Library/UI Action Vessel/XUIAvrgMDValue")]
public class XUIAvrgMDValue : MonoBehaviour
@@ -49,7 +50,7 @@ namespace XericUI.ReflectionUIGenerator
// ============ UI 文本插槽 ============
- [Header("UI 文本插槽")]
+ [Header("UI 基类插槽")]
[SerializeField, Tooltip("字段标签文本 — 显示 \"名称 (只读) ⚠警告\",为 null 则不显示标签")]
#if dUI_TextMeshPro
protected TMPro.TMP_Text _fieldLabelText;
@@ -57,13 +58,6 @@ namespace XericUI.ReflectionUIGenerator
protected UnityEngine.UI.Text _fieldLabelText;
#endif
- [SerializeField, Tooltip("值显示文本 — 可为 null(Slider/Color/Texture 子类不依赖文本)")]
-#if dUI_TextMeshPro
- protected TMPro.TMP_Text _valueDisplayText;
-#else
- protected UnityEngine.UI.Text _valueDisplayText;
-#endif
-
[SerializeField, Tooltip("单位文本 — 可为 null")]
#if dUI_TextMeshPro
protected TMPro.TMP_Text _unitText;
@@ -71,6 +65,9 @@ namespace XericUI.ReflectionUIGenerator
protected UnityEngine.UI.Text _unitText;
#endif
+ [SerializeField, Tooltip("单位容器 Transform — 单位文本为空时 SetActive(false) 隐藏")]
+ protected Transform _unitTransform;
+
// ============ 公共属性 ============
/// 绑定的元数据引用
@@ -102,7 +99,8 @@ namespace XericUI.ReflectionUIGenerator
BoundMetaData = metaData;
CurrentValidationState = ValidationState.Normal;
- // 子类覆写点
+ // 单位可见性:无单位文本则隐藏单位节点
+ ApplyUnitVisibility();
}
///
@@ -118,8 +116,10 @@ namespace XericUI.ReflectionUIGenerator
// 重置 UI 文本
if (_fieldLabelText != null) _fieldLabelText.text = "";
- if (_valueDisplayText != null) _valueDisplayText.text = "";
if (_unitText != null) _unitText.text = "";
+
+ // 重置单位可见性
+ if (_unitTransform != null) _unitTransform.gameObject.SetActive(true);
}
// ============ 核心绑定接口 ============
@@ -155,34 +155,17 @@ namespace XericUI.ReflectionUIGenerator
///
/// 根据值和验证状态更新 UI 显示
- /// 子类可覆写以处理专属组件更新(Slider.value, Image.color 等)
- /// 基类负责合成标签文本、值文本颜色、单位文本
+ /// 子类必须覆写以处理专属组件更新(Slider.value, Image.color 等),
+ /// 并在覆写中调用 base.UpdateValueDisplay(value, state) 以刷新标签。
///
protected virtual void UpdateValueDisplay(object value, ValidationState state)
{
// 1. 字段标签合成
if (_fieldLabelText != null)
- {
- string label = BuildLabel(state);
- _fieldLabelText.text = label;
- }
+ _fieldLabelText.text = BuildLabel(state);
- // 2. 值显示
- if (_valueDisplayText != null)
- {
- string display = CurrentAccessor?.FormatDisplay(value) ?? value?.ToString() ?? "";
- _valueDisplayText.text = display;
-
- _valueDisplayText.color = state == ValidationState.Invalid
- ? Color.red
- : state == ValidationState.Warning
- ? new Color(1f, 0.92f, 0.016f) // yellow
- : Color.white;
- }
-
- // 3. 单位文本
- if (_unitText != null)
- _unitText.text = BoundMetaData?.UnitLabelName ?? "";
+ // 2. 单位文本 + 可见性
+ ApplyUnitText();
}
///
@@ -211,6 +194,32 @@ namespace XericUI.ReflectionUIGenerator
return sb.ToString();
}
+ ///
+ /// 更新单位文本并控制可见性
+ ///
+ protected void ApplyUnitText()
+ {
+ string unit = BoundMetaData?.UnitLabelName;
+ bool hasUnit = !string.IsNullOrEmpty(unit);
+
+ if (_unitText != null)
+ _unitText.text = hasUnit ? unit : "";
+
+ if (_unitTransform != null)
+ _unitTransform.gameObject.SetActive(hasUnit);
+ }
+
+ ///
+ /// 仅刷新单位可见性(不更新文本内容)
+ ///
+ protected void ApplyUnitVisibility()
+ {
+ if (_unitTransform == null) return;
+
+ string unit = BoundMetaData?.UnitLabelName;
+ _unitTransform.gameObject.SetActive(!string.IsNullOrEmpty(unit));
+ }
+
// ============ 验证状态回调 ============
///
@@ -224,16 +233,6 @@ namespace XericUI.ReflectionUIGenerator
// 刷新标签文本(警告/无效标记在标签上)
if (_fieldLabelText != null)
_fieldLabelText.text = BuildLabel(state);
-
- // 值文本颜色
- if (_valueDisplayText != null)
- {
- _valueDisplayText.color = state == ValidationState.Invalid
- ? Color.red
- : state == ValidationState.Warning
- ? new Color(1f, 0.92f, 0.016f)
- : Color.white;
- }
}
// ============ 元数据广播 ============