添加表格的强制样式更新。

优化样式状态集,添加了样式集基于默认值的默认样式路径。
优化样式表按钮等组件的刷新功能。
This commit is contained in:
2026-06-28 23:08:17 +08:00
parent c98503239f
commit f20033743d
7 changed files with 715 additions and 535 deletions
+11 -1
View File
@@ -37,6 +37,9 @@ namespace XericUIEditor.XTable
m_ColWidthsProp = serializedObject.FindProperty("m_ColWidths");
m_DefaultStyleNsProp = serializedObject.FindProperty("m_DefaultStyleNamespace");
m_ScrollRectProp = serializedObject.FindProperty("m_ScrollRect");
// 同步表格的 ChildrenVisible 状态到编辑器 toggle
m_ShowChildren = m_Table.ChildrenVisible;
}
public override void OnInspectorGUI()
@@ -78,7 +81,14 @@ namespace XericUIEditor.XTable
if (GUILayout.Button("重新生成表格", GUILayout.Height(26)))
{
m_Table.FullRebuild();
m_Table.SetChildrenVisible(!m_ShowChildren);
m_Table.SetChildrenVisible(m_ShowChildren);
}
if (GUILayout.Button("强制刷新样式", GUILayout.Height(26)))
{
XericLibrary.Runtime.SuperStyleSheet.StyleManager.ForceRefresh();
m_Table.FullRebuild();
m_Table.SetChildrenVisible(m_ShowChildren);
}
EditorGUILayout.Space(4);
@@ -8,5 +8,6 @@ namespace: default
.NormalColor = (1,1,1,1)
.HighlightedColor = (0.96,0.96,0.96,1)
.PressedColor = (0.78,0.78,0.78,1)
.DisabledColor = (0.78,0.78,0.78,0.5)
.SelectedColor = (0.96,0.96,0.96,1)
.DisabledColor = (0.6,0.6,0.6,0.8)
}
+25 -8
View File
@@ -9,34 +9,36 @@ namespace XericUI.Core.StyleSheetUI
/// <summary>
/// 样式表驱动的 UI 交互状态块——仿 ColorBlock 设计。
/// 集中管理 Normal/Highlighted/Pressed/Selected/Disabled 五种状态的 StyleField。
/// 职责单一:仅保存一组样式属性(如仅颜色、或仅纹理)。
/// 在组件上声明多个实例分别实现颜色切换和纹理切换。
/// </summary>
[Serializable]
public class StyleSheetState
{
private const string k_DefaultColorBasePath = "/button/TargetGraphic/ColorTint";
private const string k_DefaultTextureBasePath = "/button/TargetGraphic/SpriteState";
private const string k_DefaultNamespace = "default";
#region 序列化字段
[Header("五态样式路径")]
[SerializeField]
[Tooltip("正常状态")]
private StyleField m_Normal = new StyleField();
private StyleField m_Normal = new StyleField { Namespace = k_DefaultNamespace, StylePath = k_DefaultColorBasePath + "/NormalColor" };
[SerializeField]
[Tooltip("高亮状态")]
private StyleField m_Highlighted = new StyleField();
private StyleField m_Highlighted = new StyleField { Namespace = k_DefaultNamespace, StylePath = k_DefaultColorBasePath + "/HighlightedColor" };
[SerializeField]
[Tooltip("按下状态")]
private StyleField m_Pressed = new StyleField();
private StyleField m_Pressed = new StyleField { Namespace = k_DefaultNamespace, StylePath = k_DefaultColorBasePath + "/PressedColor" };
[SerializeField]
[Tooltip("选中状态")]
private StyleField m_Selected = new StyleField();
private StyleField m_Selected = new StyleField { Namespace = k_DefaultNamespace, StylePath = k_DefaultColorBasePath + "/SelectedColor" };
[SerializeField]
[Tooltip("禁用状态")]
private StyleField m_Disabled = new StyleField();
private StyleField m_Disabled = new StyleField { Namespace = k_DefaultNamespace, StylePath = k_DefaultColorBasePath + "/DisabledColor" };
[Header("过渡")]
[SerializeField]
@@ -66,9 +68,24 @@ namespace XericUI.Core.StyleSheetUI
m_Normal, m_Highlighted, m_Pressed, m_Selected, m_Disabled
};
/// <summary>默认实例</summary>
/// <summary>默认实例(五态默认匹配 ColorTint 颜色块)</summary>
public static StyleSheetState Default => new StyleSheetState();
/// <summary>
/// 创建纹理五态样式块,StylePath 默认匹配 SpriteState 块。
/// </summary>
public static StyleSheetState CreateTexture(string ns = k_DefaultNamespace)
{
var state = new StyleSheetState();
state.Normal.StylePath = k_DefaultTextureBasePath + "/NormalSprite";
state.Highlighted.StylePath = k_DefaultTextureBasePath + "/HighlightedSprite";
state.Pressed.StylePath = k_DefaultTextureBasePath + "/PressedSprite";
state.Selected.StylePath = k_DefaultTextureBasePath + "/SelectedSprite";
state.Disabled.StylePath = k_DefaultTextureBasePath + "/DisabledSprite";
foreach (var f in state.AllFields) f.Namespace = ns;
return state;
}
#endregion
#region 查找
@@ -153,7 +153,7 @@ RectTransform:
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1479413702}
- {fileID: 1558175926}
- {fileID: 1278174473}
m_Father: {fileID: 1305945111}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 1}
@@ -605,7 +605,7 @@ RectTransform:
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 360, y: 60}
m_SizeDelta: {x: 260, y: 160}
m_Pivot: {x: 0, y: 1}
--- !u!114 &779072859
MonoBehaviour:
@@ -636,7 +636,7 @@ MonoBehaviour:
- Text: Age
Image: {fileID: 0}
Prefab: {fileID: 0}
StyleNamespace: xeric_table_default
StyleNamespace:
- Text: City
Image: {fileID: 0}
Prefab: {fileID: 0}
@@ -764,7 +764,7 @@ MonoBehaviour:
- Text: 25
Image: {fileID: 0}
Prefab: {fileID: 0}
StyleNamespace:
StyleNamespace: xeric_table_default
- Text: NYC
Image: {fileID: 0}
Prefab: {fileID: 0}
@@ -4727,14 +4727,14 @@ MonoBehaviour:
StyleNamespace:
MergeDescriptors: []
m_RowHeights:
- 20
- 20
- 20
- 40
- 40
- 40
- 40
m_ColWidths:
- 80
- 80
- 100
- 100
m_DefaultStyleNamespace: xeric_table_default
m_ScrollRect: {fileID: 176805031}
--- !u!222 &779072860
@@ -4745,6 +4745,140 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 779072857}
m_CullTransparentMesh: 1
--- !u!1 &824962586
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 824962587}
- component: {fileID: 824962589}
- component: {fileID: 824962588}
m_Layer: 5
m_Name: Text (TMP)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &824962587
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 824962586}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1278174473}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &824962588
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 824962586}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: Button
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4281479730
m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 24
m_fontSizeBase: 24
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 2
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_enableWordWrapping: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!222 &824962589
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 824962586}
m_CullTransparentMesh: 1
--- !u!224 &879192284 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 3719551361696879033, guid: 1715f06fee075eb45b68d43575e9aa88, type: 3}
@@ -4954,6 +5088,192 @@ Transform:
- {fileID: 1830323039}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1278174472
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1278174473}
- component: {fileID: 1278174476}
- component: {fileID: 1278174475}
- component: {fileID: 1278174474}
m_Layer: 5
m_Name: Button
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1278174473
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1278174472}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 824962587}
m_Father: {fileID: 29274970}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 202.5, y: 0}
m_SizeDelta: {x: 160, y: 30}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1278174474
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1278174472}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ac135f8a0c9ac114aabb20e033ab1331, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 1278174475}
m_OnClick:
m_PersistentCalls:
m_Calls: []
m_ColorState:
m_Normal:
_namespace: default
_stylePath: /button/TargetGraphic/ColorTint/NormalColor
_member:
StylePath: /button/TargetGraphic/ColorTint/NormalColor
CurrentNamespace: default
m_Highlighted:
_namespace: default
_stylePath: /button/TargetGraphic/ColorTint/HighlightedColor
_member:
StylePath: /button/TargetGraphic/ColorTint/HighlightedColor
CurrentNamespace: default
m_Pressed:
_namespace: default
_stylePath: /button/TargetGraphic/ColorTint/PressedColor
_member:
StylePath: /button/TargetGraphic/ColorTint/PressedColor
CurrentNamespace: default
m_Selected:
_namespace: default
_stylePath: /button/TargetGraphic/ColorTint/SelectedColor
_member:
StylePath: /button/TargetGraphic/ColorTint/SelectedColor
CurrentNamespace: default
m_Disabled:
_namespace: default
_stylePath: /button/TargetGraphic/ColorTint/DisabledColor
_member:
StylePath: /button/TargetGraphic/ColorTint/DisabledColor
CurrentNamespace: default
m_FadeDuration: 0.1
m_TextureState:
m_Normal:
_namespace: default
_stylePath: /button/TargetGraphic/ColorTint/NormalColor
_member:
StylePath: /button/TargetGraphic/ColorTint/NormalColor
CurrentNamespace: default
m_Highlighted:
_namespace: default
_stylePath: /button/TargetGraphic/ColorTint/HighlightedColor
_member:
StylePath: /button/TargetGraphic/ColorTint/HighlightedColor
CurrentNamespace: default
m_Pressed:
_namespace: default
_stylePath: /button/TargetGraphic/ColorTint/PressedColor
_member:
StylePath: /button/TargetGraphic/ColorTint/PressedColor
CurrentNamespace: default
m_Selected:
_namespace: default
_stylePath: /button/TargetGraphic/ColorTint/SelectedColor
_member:
StylePath: /button/TargetGraphic/ColorTint/SelectedColor
CurrentNamespace: default
m_Disabled:
_namespace: default
_stylePath: /button/TargetGraphic/ColorTint/DisabledColor
_member:
StylePath: /button/TargetGraphic/ColorTint/DisabledColor
CurrentNamespace: default
m_FadeDuration: 0.1
m_EnableStyleTransition: 1
--- !u!114 &1278174475
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1278174472}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!222 &1278174476
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1278174472}
m_CullTransparentMesh: 1
--- !u!1 &1305945107
GameObject:
m_ObjectHideFlags: 0
@@ -5243,192 +5563,6 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1479413701}
m_CullTransparentMesh: 1
--- !u!1 &1558175925
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1558175926}
- component: {fileID: 1558175929}
- component: {fileID: 1558175928}
- component: {fileID: 1558175927}
m_Layer: 5
m_Name: Button
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1558175926
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1558175925}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1966406954}
m_Father: {fileID: 29274970}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 159.8, y: 0}
m_SizeDelta: {x: 160, y: 30}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1558175927
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1558175925}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ac135f8a0c9ac114aabb20e033ab1331, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 1558175928}
m_OnClick:
m_PersistentCalls:
m_Calls: []
m_ColorState:
m_Normal:
_namespace: xeric_table_default
_stylePath:
_member:
StylePath:
CurrentNamespace: xeric_table_default
m_Highlighted:
_namespace: xeric_table_default
_stylePath:
_member:
StylePath:
CurrentNamespace: xeric_table_default
m_Pressed:
_namespace: xeric_table_default
_stylePath:
_member:
StylePath:
CurrentNamespace: xeric_table_default
m_Selected:
_namespace: xeric_table_default
_stylePath:
_member:
StylePath:
CurrentNamespace: xeric_table_default
m_Disabled:
_namespace: xeric_table_default
_stylePath:
_member:
StylePath:
CurrentNamespace: xeric_table_default
m_FadeDuration: 0.1
m_TextureState:
m_Normal:
_namespace:
_stylePath:
_member:
StylePath:
CurrentNamespace:
m_Highlighted:
_namespace:
_stylePath:
_member:
StylePath:
CurrentNamespace:
m_Pressed:
_namespace:
_stylePath:
_member:
StylePath:
CurrentNamespace:
m_Selected:
_namespace:
_stylePath:
_member:
StylePath:
CurrentNamespace:
m_Disabled:
_namespace:
_stylePath:
_member:
StylePath:
CurrentNamespace:
m_FadeDuration: 0.1
m_EnableStyleTransition: 1
--- !u!114 &1558175928
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1558175925}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!222 &1558175929
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1558175925}
m_CullTransparentMesh: 1
--- !u!1 &1586214055
GameObject:
m_ObjectHideFlags: 0
@@ -6014,140 +6148,6 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1966406953
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1966406954}
- component: {fileID: 1966406956}
- component: {fileID: 1966406955}
m_Layer: 5
m_Name: Text (TMP)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1966406954
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1966406953}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1558175926}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1966406955
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1966406953}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: Button
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4281479730
m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 24
m_fontSizeBase: 24
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 2
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_enableWordWrapping: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!222 &1966406956
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1966406953}
m_CullTransparentMesh: 1
--- !u!224 &1986399782 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 101967088653580022, guid: f601d441cf135fe479d319c5eb01abd8, type: 3}
+168 -151
View File
@@ -1,203 +1,220 @@
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using XericLibrary.Runtime.SuperStyleSheet;
using XericUI.Core.StyleSheetUI;
using XericUI.Helper;
namespace XericUI.OverrideUI
{
/// <summary>
/// 基于 SuperStyleSheet 的按钮组件。
/// 通过两个独立的 StyleSheetState 实例分别管理颜色和纹理的五态样式切换,
/// 替代 Unity 内置的 ColorBlock 和 SpriteState。
/// </summary>
[AddComponentMenu("Xeric UI Vessel/UI/Style Button", 51)]
public class XericStyleButton : Button, IStyleRefreshable
{
#region 序列化字段
/// <summary>
/// 基于 SuperStyleSheet 的按钮组件。
/// 通过 TransitionMode 选择颜色切换、纹理切换或两者并用,
/// 替代 Unity 内置的 ColorBlock 和 SpriteState。
/// </summary>
[AddComponentMenu("Xeric UI Vessel/UI/Style Button", 51)]
public class XericStyleButton : Button, IStyleRefreshable
{
/// <summary>样式过渡模式</summary>
public enum TransitionMode
{
/// <summary>仅颜色切换</summary>
Color,
/// <summary>仅纹理/Sprite 切换</summary>
Sprite,
/// <summary>颜色 + 纹理切换</summary>
ColorAndSprite
}
[Header("样式表状态")]
[SerializeField]
[Tooltip("五态颜色样式块")]
#region 序列化字段
[Header("过渡模式")]
[SerializeField]
[Tooltip("选择颜色 / 纹理 / 同时切换")]
private TransitionMode m_TransitionMode = TransitionMode.ColorAndSprite;
[Header("样式表状态")] [SerializeField]
[Tooltip("五态颜色样式块(ColorTint)")]
private StyleSheetState m_ColorState = StyleSheetState.Default;
[SerializeField]
[Tooltip("五态纹理样式块")]
private StyleSheetState m_TextureState = StyleSheetState.Default;
[Tooltip("五态纹理样式块(SpriteState)")]
private StyleSheetState m_TextureState = StyleSheetState.CreateTexture();
[SerializeField]
[Tooltip("启用样式表驱动过渡(关闭则回退为 Unity ColorBlock)")]
private bool m_EnableStyleTransition = true;
[SerializeField] [Tooltip("启用样式表驱动过渡(关闭则回退为 Unity ColorBlock)")]
private bool m_EnableStyleTransition = true;
#endregion
#endregion
#region 运行时
#region 运行时
[System.NonSerialized] private StyleSheetSelectionState m_CurrentState = StyleSheetSelectionState.Normal;
[System.NonSerialized] private Graphic m_TargetGraphic;
[System.NonSerialized] private Image m_TargetImage;
[System.NonSerialized] private StyleSheetSelectionState m_CurrentState = StyleSheetSelectionState.Normal;
[System.NonSerialized] private Graphic m_TargetGraphic;
[System.NonSerialized] private Image m_TargetImage;
#endregion
#endregion
#region 生命周期
#region 生命周期
protected override void Awake()
{
base.Awake();
m_TargetGraphic = targetGraphic;
m_TargetImage = m_TargetGraphic as Image;
}
protected override void Awake()
{
base.Awake();
m_TargetGraphic = targetGraphic;
m_TargetImage = m_TargetGraphic as Image;
}
protected override void OnEnable()
{
base.OnEnable();
protected override void OnEnable()
{
base.OnEnable();
RevalidateStyles();
RevalidateStyles();
StyleRefreshManager.Register(this);
ApplyForState(m_CurrentState);
}
StyleRefreshManager.Register(this);
ApplyForState(m_CurrentState);
}
#if UNITY_EDITOR
protected override void OnValidate()
{
base.OnValidate();
RevalidateStyles();
ApplyForState(m_CurrentState);
}
protected override void OnValidate()
{
base.OnValidate();
RevalidateStyles();
ApplyForState(m_CurrentState);
}
#endif
private void RevalidateStyles()
{
m_ColorState?.UnsubscribeAll(OnStyleChanged);
m_TextureState?.UnsubscribeAll(OnStyleChanged);
private void RevalidateStyles()
{
m_ColorState?.UnsubscribeAll(OnStyleChanged);
m_TextureState?.UnsubscribeAll(OnStyleChanged);
m_ColorState?.RegisterAll();
m_TextureState?.RegisterAll();
m_ColorState?.SubscribeAll(OnStyleChanged);
m_TextureState?.SubscribeAll(OnStyleChanged);
}
m_ColorState?.RegisterAll();
m_TextureState?.RegisterAll();
m_ColorState?.SubscribeAll(OnStyleChanged);
m_TextureState?.SubscribeAll(OnStyleChanged);
}
protected override void OnDisable()
{
StyleRefreshManager.Unregister(this);
protected override void OnDisable()
{
StyleRefreshManager.Unregister(this);
m_ColorState?.UnsubscribeAll(OnStyleChanged);
m_TextureState?.UnsubscribeAll(OnStyleChanged);
m_ColorState?.UnregisterAll();
m_TextureState?.UnregisterAll();
m_ColorState?.UnsubscribeAll(OnStyleChanged);
m_TextureState?.UnsubscribeAll(OnStyleChanged);
m_ColorState?.UnregisterAll();
m_TextureState?.UnregisterAll();
base.OnDisable();
}
base.OnDisable();
}
#endregion
#endregion
#region 状态过渡
#region 状态过渡
protected override void DoStateTransition(SelectionState state, bool instant)
{
if (!gameObject.activeInHierarchy) return;
protected override void DoStateTransition(SelectionState state, bool instant)
{
if (!gameObject.activeInHierarchy) return;
m_CurrentState = (StyleSheetSelectionState)(int)state;
m_CurrentState = (StyleSheetSelectionState)(int)state;
if (m_EnableStyleTransition)
ApplyForState(m_CurrentState, instant);
else
base.DoStateTransition(state, instant);
}
if (m_EnableStyleTransition)
ApplyForState(m_CurrentState, instant);
else
base.DoStateTransition(state, instant);
}
#endregion
#endregion
#region 样式应用
#region 样式应用
public void RefreshStyle()
{
ApplyForState(m_CurrentState, false);
}
public void RefreshStyle()
{
ApplyForState(m_CurrentState, false);
}
private void ApplyForState(StyleSheetSelectionState state, bool instant = false)
{
// 颜色
if (m_ColorState != null)
{
StyleField colorField = m_ColorState.GetForState(state);
if (colorField != null && m_TargetGraphic != null)
{
StyleValue val = colorField.GetValue();
if (val != null)
m_TargetGraphic.CrossFadeColor((Color)val,
instant ? 0f : m_ColorState.FadeDuration, true, true);
}
}
private void ApplyForState(StyleSheetSelectionState state, bool instant = false)
{
if (m_TransitionMode == TransitionMode.Color || m_TransitionMode == TransitionMode.ColorAndSprite)
{
if (m_ColorState != null)
{
StyleField colorField = m_ColorState.GetForState(state);
if (colorField != null && m_TargetGraphic != null)
{
StyleValue val = colorField.GetValue();
if (val != null)
m_TargetGraphic.CrossFadeColor((Color)val,
instant ? 0f : m_ColorState.FadeDuration, true, true);
}
}
}
// 纹理
if (m_TextureState != null && m_TargetImage != null)
{
StyleField texField = m_TextureState.GetForState(state);
if (texField != null)
{
StyleValue val = texField.GetValue();
Texture2D tex = val?.GetValueAs<Texture2D>();
if (tex != null)
m_TargetImage.overrideSprite = Sprite.Create(tex,
new Rect(0, 0, tex.width, tex.height),
new Vector2(0.5f, 0.5f));
}
}
}
if (m_TransitionMode == TransitionMode.Sprite || m_TransitionMode == TransitionMode.ColorAndSprite)
{
if (m_TextureState != null && m_TargetImage != null)
{
StyleField texField = m_TextureState.GetForState(state);
if (texField != null)
{
StyleValue val = texField.GetValue();
Texture2D tex = val?.GetValueAs<Texture2D>();
if (tex != null)
m_TargetImage.overrideSprite = Sprite.Create(tex,
new Rect(0, 0, tex.width, tex.height),
new Vector2(0.5f, 0.5f));
}
}
}
}
private void OnStyleChanged(StyleValue _)
{
if (gameObject.activeInHierarchy)
ApplyForState(m_CurrentState);
}
private void OnStyleChanged(StyleValue _)
{
if (gameObject.activeInHierarchy)
ApplyForState(m_CurrentState);
}
#endregion
#endregion
#region 组件替换
#region 组件替换
#if UNITY_EDITOR
[UnityEditor.MenuItem("CONTEXT/XericStyleButton/Xeric UI/强制刷新样式", false, 1)]
private static void ForceRefreshStyle(UnityEditor.MenuCommand command)
{
StyleRefreshManager.ForceRefreshAll();
}
[UnityEditor.MenuItem("CONTEXT/XericStyleButton/Xeric UI/强制刷新样式", false, 1)]
private static void ForceRefreshStyle(UnityEditor.MenuCommand command)
{
StyleRefreshManager.ForceRefreshAll();
}
[UnityEditor.MenuItem("CONTEXT/Button/Replace To/Xeric (Style)", true)]
private static bool ValidateReplaceToStyleButton(UnityEditor.MenuCommand command)
=> command.context is Button and not XericStyleButton;
[UnityEditor.MenuItem("CONTEXT/Button/Replace To/Xeric (Style)", true)]
private static bool ValidateReplaceToStyleButton(UnityEditor.MenuCommand command)
=> command.context is Button and not XericStyleButton;
[UnityEditor.MenuItem("CONTEXT/Button/Replace To/Xeric (Style)", false, 11)]
private static void ReplaceToStyleButton(UnityEditor.MenuCommand command)
=> command.ReplaceCommandContext<Button, XericStyleButton,
(Graphic targetGraphic, ButtonClickedEvent onClick, Navigation navigation)>(
o => (o.targetGraphic, o.onClick, o.navigation),
(t, d) =>
{
t.targetGraphic = d.targetGraphic;
t.onClick = d.onClick;
t.navigation = d.navigation;
});
[UnityEditor.MenuItem("CONTEXT/Button/Replace To/Xeric (Style)", false, 11)]
private static void ReplaceToStyleButton(UnityEditor.MenuCommand command)
=> command.ReplaceCommandContext<Button, XericStyleButton,
(Graphic targetGraphic, ButtonClickedEvent onClick, Navigation navigation)>(
o => (o.targetGraphic, o.onClick, o.navigation),
(t, d) =>
{
t.targetGraphic = d.targetGraphic;
t.onClick = d.onClick;
t.navigation = d.navigation;
});
[UnityEditor.MenuItem("CONTEXT/Button/Replace To/Unity Button", true)]
private static bool ValidateReplaceStyleToUnity(UnityEditor.MenuCommand command)
=> command.context is XericStyleButton;
[UnityEditor.MenuItem("CONTEXT/Button/Replace To/Unity Button", true)]
private static bool ValidateReplaceStyleToUnity(UnityEditor.MenuCommand command)
=> command.context is XericStyleButton;
[UnityEditor.MenuItem("CONTEXT/Button/Replace To/Unity Button", false, 100)]
private static void ReplaceStyleToUnity(UnityEditor.MenuCommand command)
=> command.ReplaceCommandContext<XericStyleButton, Button,
(Graphic targetGraphic, ButtonClickedEvent onClick, Navigation navigation)>(
o => (o.targetGraphic, o.onClick, o.navigation),
(t, d) =>
{
t.targetGraphic = d.targetGraphic;
t.onClick = d.onClick;
t.navigation = d.navigation;
});
[UnityEditor.MenuItem("CONTEXT/Button/Replace To/Unity Button", false, 100)]
private static void ReplaceStyleToUnity(UnityEditor.MenuCommand command)
=> command.ReplaceCommandContext<XericStyleButton, Button,
(Graphic targetGraphic, ButtonClickedEvent onClick, Navigation navigation)>(
o => (o.targetGraphic, o.onClick, o.navigation),
(t, d) =>
{
t.targetGraphic = d.targetGraphic;
t.onClick = d.onClick;
t.navigation = d.navigation;
});
#endif
#endregion
}
}
#endregion
}
}
+49 -25
View File
@@ -9,20 +9,38 @@ namespace XericUI.OverrideUI
{
/// <summary>
/// 基于 SuperStyleSheet 的开关组件。
/// 使用两个 StyleSheetState 实例管理五态颜色和纹理样式,
/// 通过 TransitionMode 选择颜色切换、纹理切换或两者并用,
/// 额外支持 isOn 覆盖和 Checkmark 样式。
/// </summary>
[AddComponentMenu("Xeric UI Vessel/UI/Style Toggle", 52)]
public class XericStyleToggle : Toggle, IStyleRefreshable
{
/// <summary>样式过渡模式</summary>
public enum TransitionMode
{
/// <summary>仅颜色切换</summary>
Color,
/// <summary>仅纹理/Sprite 切换</summary>
Sprite,
/// <summary>颜色 + 纹理切换</summary>
ColorAndSprite
}
#region 序列化字段
[Header("过渡模式")]
[SerializeField]
[Tooltip("选择颜色 / 纹理 / 同时切换")]
private TransitionMode m_TransitionMode = TransitionMode.ColorAndSprite;
[Header("样式表状态")]
[SerializeField]
[Tooltip("五态颜色样式块(ColorTint)")]
private StyleSheetState m_ColorState = StyleSheetState.Default;
[SerializeField]
private StyleSheetState m_TextureState = StyleSheetState.Default;
[Tooltip("五态纹理样式块(SpriteState)")]
private StyleSheetState m_TextureState = StyleSheetState.CreateTexture();
[Header("Toggle 专用")]
[SerializeField]
@@ -163,37 +181,43 @@ namespace XericUI.OverrideUI
private void ApplyForState(StyleSheetSelectionState state, bool instant = false)
{
// 颜色:On 覆盖优先
StyleField colorField = isOn && m_OnOverrideColor?.GetValue() != null
? m_OnOverrideColor
: m_ColorState?.GetForState(state);
if (colorField != null && m_TargetGraphic != null)
if (m_TransitionMode == TransitionMode.Color || m_TransitionMode == TransitionMode.ColorAndSprite)
{
StyleValue val = colorField.GetValue();
if (val != null)
// 颜色:On 覆盖优先
StyleField colorField = isOn && m_OnOverrideColor?.GetValue() != null
? m_OnOverrideColor
: m_ColorState?.GetForState(state);
if (colorField != null && m_TargetGraphic != null)
{
float dur = instant ? 0f : (m_ColorState?.FadeDuration ?? 0.1f);
m_TargetGraphic.CrossFadeColor((Color)val, dur, true, true);
StyleValue val = colorField.GetValue();
if (val != null)
{
float dur = instant ? 0f : (m_ColorState?.FadeDuration ?? 0.1f);
m_TargetGraphic.CrossFadeColor((Color)val, dur, true, true);
}
}
}
// 纹理:On 覆盖优先
StyleField texField = isOn && m_OnOverrideTexture?.GetValue() != null
? m_OnOverrideTexture
: m_TextureState?.GetForState(state);
if (texField != null && m_TargetImage != null)
if (m_TransitionMode == TransitionMode.Sprite || m_TransitionMode == TransitionMode.ColorAndSprite)
{
StyleValue val = texField.GetValue();
Texture2D tex = val?.GetValueAs<Texture2D>();
if (tex != null)
m_TargetImage.overrideSprite = Sprite.Create(tex,
new Rect(0, 0, tex.width, tex.height),
new Vector2(0.5f, 0.5f));
// 纹理:On 覆盖优先
StyleField texField = isOn && m_OnOverrideTexture?.GetValue() != null
? m_OnOverrideTexture
: m_TextureState?.GetForState(state);
if (texField != null && m_TargetImage != null)
{
StyleValue val = texField.GetValue();
Texture2D tex = val?.GetValueAs<Texture2D>();
if (tex != null)
m_TargetImage.overrideSprite = Sprite.Create(tex,
new Rect(0, 0, tex.width, tex.height),
new Vector2(0.5f, 0.5f));
}
}
// Checkmark
// Checkmark(独立于 TransitionMode)
if (m_CheckmarkGraphic != null && m_CheckmarkStyle != null)
{
StyleValue val = m_CheckmarkStyle.GetValue();
@@ -39,6 +39,10 @@ namespace XericUI.XTable.Rendering.Component
[SerializeField] private ScrollRect m_ScrollRect;
[SerializeField]
[Tooltip("在 Hierarchy 中显示动态生成的子对象(仅编辑器,不保存到场景)")]
private bool m_ChildrenVisible;
#endregion
#region 私有字段
@@ -102,6 +106,13 @@ namespace XericUI.XTable.Rendering.Component
public int SelectEndCol => m_SelectEndCol;
public bool HasMultiSelection => m_SelectStartRow >= 0 && m_SelectEndRow >= 0;
/// <summary>动态子对象在 Hierarchy 中是否可见(仅编辑器有效)</summary>
public bool ChildrenVisible
{
get => m_ChildrenVisible;
set => SetChildrenVisible(value);
}
/// <summary>判断单元格是否在多选范围内</summary>
public bool IsInSelectionRange(int row, int col)
{
@@ -151,6 +162,15 @@ namespace XericUI.XTable.Rendering.Component
MarkDirty(TableDirtyType.All);
}
#if UNITY_EDITOR
protected override void OnValidate()
{
base.OnValidate();
// 编辑器下属性变更 / 选中组件时即刻刷新样式
MarkDirty(TableDirtyType.All);
}
#endif
protected override void OnDisable()
{
base.OnDisable();
@@ -606,6 +626,7 @@ namespace XericUI.XTable.Rendering.Component
m_DirtyFlag.Clear();
OnTableRefreshed?.Invoke();
SetChildrenVisible(m_ChildrenVisible);
}
#endregion
@@ -629,7 +650,7 @@ namespace XericUI.XTable.Rendering.Component
bgRt.sizeDelta = new Vector2(m_TotalWidth, m_TotalHeight);
var bgImg = m_BackgroundGo.GetComponent<Image>();
bgImg.color = new Color(0.18f, 0.18f, 0.18f, 1f);
bgImg.color = GetStyleColor(m_DefaultStyleNamespace, "/cell/bg/color", new Color(0.18f, 0.18f, 0.18f, 1f));
bgImg.raycastTarget = false;
}
@@ -661,14 +682,15 @@ namespace XericUI.XTable.Rendering.Component
/// <summary>设置所有动态子对象的可见性(仅编辑器)</summary>
public void SetChildrenVisible(bool visible)
{
m_ChildrenVisible = visible;
#if UNITY_EDITOR
if (rectTransform == null) return;
for (int i = rectTransform.childCount - 1; i >= 0; i--)
{
var child = rectTransform.GetChild(i);
child.gameObject.hideFlags = visible
? HideFlags.DontSave // 可见但不保存
: HideFlags.DontSave | HideFlags.HideInHierarchy; // 隐藏且不保存
? HideFlags.DontSave
: HideFlags.DontSave | HideFlags.HideInHierarchy;
}
#endif
}
@@ -689,6 +711,7 @@ namespace XericUI.XTable.Rendering.Component
CreateBackground();
MarkDirty(TableDirtyType.All);
RefreshView();
SetChildrenVisible(m_ChildrenVisible);
}
#endregion
@@ -698,9 +721,82 @@ namespace XericUI.XTable.Rendering.Component
private void RenderCells(int sr, int er, int sc, int ec)
{
Color fgFallback = new Color(0.05f, 0.05f, 0.05f);
Color selectionColor = new Color(0.18f, 0.42f, 0.82f, 0.25f);
Color multiSelectColor = new Color(0.18f, 0.42f, 0.82f, 0.12f);
Color focusColor = new Color(0.22f, 0.55f, 0.95f, 0.35f);
string ns = m_DefaultStyleNamespace;
// 编辑器模式:从样式表 pull 所有颜色值
#if UNITY_EDITOR
if (!Application.isPlaying)
{
Color selectionColor = GetStyleColor(ns, "/cell/selection/bg/color", new Color(0.2f, 0.5f, 1f, 0.3f));
Color borderColor = GetStyleColor(ns, "/cell/border/bottom/color", new Color(0.35f, 0.35f, 0.35f, 0.5f));
float borderWidth = GetStyleFloat(ns, "/cell/border/bottom/width", 1f);
Color multiSelectColor = new Color(selectionColor.r, selectionColor.g, selectionColor.b, selectionColor.a * 0.4f);
Color focusColor = new Color(selectionColor.r + 0.04f, selectionColor.g + 0.13f, selectionColor.b + 0.13f, selectionColor.a * 1.4f);
for (int r = sr; r < er && r < m_RowHeights.Length; r++)
{
for (int c = sc; c < ec && c < m_ColWidths.Length; c++)
{
float cellX = GetColLeftX(c);
float cellY = -GetRowTopY(r);
float cellW = m_ColWidths[c];
float cellH = m_RowHeights[r];
XTableCellData data = TableData.GetCell(r, c);
string cellNS = (data != null && !string.IsNullOrEmpty(data.StyleNamespace))
? data.StyleNamespace : ns;
// 多选高亮
if (IsInSelectionRange(r, c))
{
var selImg = m_Assembler.GetImage("cell_multiselect");
selImg.Rect.anchoredPosition = new Vector2(cellX, cellY);
selImg.Rect.sizeDelta = new Vector2(cellW, cellH);
selImg.Image.color = (r == m_SelectedRow && c == m_SelectedCol)
? focusColor : multiSelectColor;
}
else if (r == m_SelectedRow && c == m_SelectedCol)
{
var selImg = m_Assembler.GetImage("cell_select");
selImg.Rect.anchoredPosition = new Vector2(cellX, cellY);
selImg.Rect.sizeDelta = new Vector2(cellW, cellH);
selImg.Image.color = selectionColor;
}
// 水平网格线(单元格底部)
var hLine = m_Assembler.GetImage("cell_hline");
hLine.Rect.anchoredPosition = new Vector2(cellX, cellY - cellH);
hLine.Rect.sizeDelta = new Vector2(cellW, borderWidth);
hLine.Image.color = borderColor;
// 垂直网格线(单元格右侧)
var vLine = m_Assembler.GetImage("cell_vline");
vLine.Rect.anchoredPosition = new Vector2(cellX + cellW - borderWidth, cellY);
vLine.Rect.sizeDelta = new Vector2(borderWidth, cellH);
vLine.Image.color = borderColor;
if (data == null) continue;
if (!string.IsNullOrEmpty(data.Text))
{
var txt = m_Assembler.GetText("cell_text", cellNS);
txt.Rect.anchoredPosition = new Vector2(cellX + 4, cellY);
txt.Rect.sizeDelta = new Vector2(cellW - 8, cellH);
txt.Text.text = data.Text;
txt.Text.color = GetStyleColor(cellNS, "/cell/fg/color", fgFallback);
txt.Text.fontSize = GetStyleInt(cellNS, "/cell/font/size", 14);
txt.Text.alignment = TextAlignmentOptions.Midline;
}
}
}
return;
}
#endif
// 运行时模式
Color rtSelectionColor = new Color(0.18f, 0.42f, 0.82f, 0.25f);
Color rtMultiSelectColor = new Color(0.18f, 0.42f, 0.82f, 0.12f);
Color rtFocusColor = new Color(0.22f, 0.55f, 0.95f, 0.35f);
for (int r = sr; r < er && r < m_RowHeights.Length; r++)
{
@@ -712,34 +808,29 @@ namespace XericUI.XTable.Rendering.Component
float cellH = m_RowHeights[r];
XTableCellData data = TableData.GetCell(r, c);
string cellNS = (data != null && !string.IsNullOrEmpty(data.StyleNamespace))
? data.StyleNamespace : m_DefaultStyleNamespace;
? data.StyleNamespace : ns;
// 多选范围高亮(覆盖被选中范围内的所有格)
if (IsInSelectionRange(r, c))
{
var selImg = m_Assembler.GetImage("cell_multiselect");
selImg.Rect.anchoredPosition = new Vector2(cellX, cellY);
selImg.Rect.sizeDelta = new Vector2(cellW, cellH);
selImg.Image.color = (r == m_SelectedRow && c == m_SelectedCol)
? focusColor
: multiSelectColor;
? rtFocusColor : rtMultiSelectColor;
}
// 单选高亮
else if (r == m_SelectedRow && c == m_SelectedCol)
{
var selImg = m_Assembler.GetImage("cell_select");
selImg.Rect.anchoredPosition = new Vector2(cellX, cellY);
selImg.Rect.sizeDelta = new Vector2(cellW, cellH);
selImg.Image.color = selectionColor;
selImg.Image.color = rtSelectionColor;
}
// 水平网格线
var hLine = m_Assembler.GetImage("cell_hline");
hLine.Rect.anchoredPosition = new Vector2(cellX, cellY - cellH);
hLine.Rect.sizeDelta = new Vector2(cellW, 1f);
hLine.Image.color = new Color(0.35f, 0.35f, 0.35f, 0.5f);
// 垂直网格线
var vLine = m_Assembler.GetImage("cell_vline");
vLine.Rect.anchoredPosition = new Vector2(cellX + cellW - 1, cellY);
vLine.Rect.sizeDelta = new Vector2(1f, cellH);
@@ -747,7 +838,6 @@ namespace XericUI.XTable.Rendering.Component
if (data == null) continue;
// 文本:与 cell 同位置同尺寸
if (!string.IsNullOrEmpty(data.Text))
{
var txt = m_Assembler.GetText("cell_text", cellNS);
@@ -756,7 +846,6 @@ namespace XericUI.XTable.Rendering.Component
txt.Text.text = data.Text;
#if UNITY_EDITOR
// 编辑器模式:直接 pull 样式值(cellNS 可能是个性化命名空间)
if (!Application.isPlaying)
{
txt.Text.color = GetStyleColor(cellNS, "/cell/fg/color", fgFallback);
@@ -764,8 +853,6 @@ namespace XericUI.XTable.Rendering.Component
txt.Text.alignment = TextAlignmentOptions.Midline;
}
#endif
// 运行时:颜色/字号/对齐由 StyleBoundElement 管理(push),
// GetText(_, cellNS) 已通过 BindStyle 注册了对应命名空间的 StyleField
}
}
}
@@ -879,6 +966,12 @@ namespace XericUI.XTable.Rendering.Component
return val != null ? (int)val : fallback;
}
private float GetStyleFloat(string ns, string path, float fallback)
{
StyleValue val = StyleManager.GetValue(ns, path);
return val != null ? (float)val : fallback;
}
private void EnsureDefaultStyleNamespace()
{
// 避免在样式表尚未加载时触发 HasStyle → GetValue 的命名空间不存在错误
@@ -888,11 +981,29 @@ namespace XericUI.XTable.Rendering.Component
if (!StyleManager.HasStyle(m_DefaultStyleNamespace, "/cell/bg/color"))
{
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/bg/color",
new Color(0.18f, 0.18f, 0.18f));
// 回退默认值匹配 DefaultTableStyles.xsss
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/bg/color", Color.white);
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/fg/color",
new Color(0.05f, 0.05f, 0.05f));
new Color(0.1f, 0.1f, 0.1f));
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/border/top/color",
new Color(0.8f, 0.8f, 0.8f));
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/border/top/width", 1f);
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/border/bottom/color",
new Color(0.8f, 0.8f, 0.8f));
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/border/bottom/width", 1f);
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/border/left/color",
new Color(0.8f, 0.8f, 0.8f));
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/border/left/width", 1f);
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/border/right/color",
new Color(0.8f, 0.8f, 0.8f));
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/border/right/width", 1f);
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/selection/bg/color",
new Color(0.2f, 0.5f, 1f, 0.3f));
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/font/size", 14);
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/font/alignment", "MiddleCenter");
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/font/richText", true);
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/default/height", 40f);
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/default/width", 100f);
StyleManager.ForceRefresh();
}
}