修复表格中对样式的依赖与更新

This commit is contained in:
2026-06-28 20:46:07 +08:00
parent 84b60c6835
commit 6c0478dc42
14 changed files with 5300 additions and 356 deletions
@@ -127,7 +127,7 @@ namespace XericUI.XTable.Rendering.Component
if (m_TableData == null)
m_TableData = new XTableData();
m_Assembler = new CellAssembler(rectTransform);
m_Assembler = new CellAssembler(rectTransform, m_DefaultStyleNamespace);
RecalculateTotalSize();
EnsureDefaultStyleNamespace();
CreateDefaultSampleData();
@@ -138,6 +138,8 @@ namespace XericUI.XTable.Rendering.Component
if (!Application.isPlaying)
SubscribeEditorUpdate();
else
m_Assembler.OnStyleChangeDetected += OnPoolStyleChanged;
MarkDirty(TableDirtyType.All);
}
@@ -160,6 +162,9 @@ namespace XericUI.XTable.Rendering.Component
m_ScrollRect.onValueChanged.RemoveListener(OnScrollValueChanged);
UnsubscribeEditorUpdate();
if (m_Assembler != null)
m_Assembler.OnStyleChangeDetected -= OnPoolStyleChanged;
// 销毁所有动态生成的对象
if (m_Assembler != null)
m_Assembler.DestroyAll();
@@ -548,7 +553,7 @@ namespace XericUI.XTable.Rendering.Component
if (m_Assembler == null)
{
if (rectTransform != null)
m_Assembler = new CellAssembler(rectTransform);
m_Assembler = new CellAssembler(rectTransform, m_DefaultStyleNamespace);
else return;
}
@@ -678,7 +683,7 @@ namespace XericUI.XTable.Rendering.Component
m_TableData = new XTableData();
m_Assembler = new CellAssembler(rectTransform);
m_Assembler = new CellAssembler(rectTransform, m_DefaultStyleNamespace);
RecalculateTotalSize();
CreateDefaultSampleData();
CreateBackground();
@@ -692,12 +697,10 @@ namespace XericUI.XTable.Rendering.Component
private void RenderCells(int sr, int er, int sc, int ec)
{
Color fgColor = GetStyleColor(m_DefaultStyleNamespace, "/cell/fg/color",
new Color(0.05f, 0.05f, 0.05f));
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);
int fontSize = GetStyleInt(m_DefaultStyleNamespace, "/cell/font/size", 14);
for (int r = sr; r < er && r < m_RowHeights.Length; r++)
{
@@ -708,6 +711,8 @@ namespace XericUI.XTable.Rendering.Component
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 : m_DefaultStyleNamespace;
// 多选范围高亮(覆盖被选中范围内的所有格)
if (IsInSelectionRange(r, c))
@@ -742,16 +747,25 @@ namespace XericUI.XTable.Rendering.Component
if (data == null) continue;
// 文本:与 cell 同位置同尺寸,TMP 内部 Midline 对齐实现居中
// 文本:与 cell 同位置同尺寸
if (!string.IsNullOrEmpty(data.Text))
{
var txt = m_Assembler.GetText("cell_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 = fgColor;
txt.Text.fontSize = fontSize;
txt.Text.alignment = TextAlignmentOptions.Midline;
#if UNITY_EDITOR
// 编辑器模式:直接 pull 样式值(cellNS 可能是个性化命名空间)
if (!Application.isPlaying)
{
txt.Text.color = GetStyleColor(cellNS, "/cell/fg/color", fgFallback);
txt.Text.fontSize = GetStyleInt(cellNS, "/cell/font/size", 14);
txt.Text.alignment = TextAlignmentOptions.Midline;
}
#endif
// 运行时:颜色/字号/对齐由 StyleBoundElement 管理(push),
// GetText(_, cellNS) 已通过 BindStyle 注册了对应命名空间的 StyleField
}
}
}
@@ -867,6 +881,11 @@ namespace XericUI.XTable.Rendering.Component
private void EnsureDefaultStyleNamespace()
{
// 避免在样式表尚未加载时触发 HasStyle → GetValue 的命名空间不存在错误
var namespaces = StyleManager.GetAvailableNamespaces();
if (namespaces == null || !namespaces.Contains(m_DefaultStyleNamespace))
return;
if (!StyleManager.HasStyle(m_DefaultStyleNamespace, "/cell/bg/color"))
{
StyleManager.AddDynamicStyle(m_DefaultStyleNamespace, "/cell/bg/color",
@@ -884,6 +903,9 @@ namespace XericUI.XTable.Rendering.Component
private void MarkDirty(TableDirtyType type) => m_DirtyFlag.Mark(type);
/// <summary>运行时样式变更回调:标记脏数据,下一帧重绘</summary>
private void OnPoolStyleChanged() => MarkDirty(TableDirtyType.StyleChanged);
private void OnScrollValueChanged(Vector2 _) => MarkDirty(TableDirtyType.ViewChanged);
#endregion
@@ -42,6 +42,12 @@ namespace XericUI.XTable.Rendering.Elements
/// <summary>池根节点(所有回收对象均挂在此节点下,节点本身处于 inactive)</summary>
public Transform PoolRoot => m_PoolRoot;
/// <summary>运行时的默认样式命名空间(编辑器下为 null,不绑定)</summary>
private string m_DefaultStyleNamespace;
/// <summary>所有已绑定的 StyleBoundElement 回调集合(用于样式变更时通知外部)</summary>
public event System.Action OnStyleChangeDetected;
private Stack<PooledImage> m_ImagePool = new Stack<PooledImage>();
private Stack<PooledText> m_TextPool = new Stack<PooledText>();
private List<PooledImage> m_ActiveImages = new List<PooledImage>();
@@ -54,9 +60,10 @@ namespace XericUI.XTable.Rendering.Elements
#region 构造函数与析构
public CellAssembler(Transform parent)
public CellAssembler(Transform parent, string defaultStyleNamespace = null)
{
m_Parent = parent;
m_DefaultStyleNamespace = defaultStyleNamespace;
GameObject poolRoot = new GameObject("_CellPool");
poolRoot.hideFlags = POOL_FLAGS;
@@ -120,7 +127,7 @@ namespace XericUI.XTable.Rendering.Elements
#region 池操作
public PooledImage GetImage(string name = "cell_img")
public PooledImage GetImage(string name = "cell_img", string styleNamespace = null)
{
PooledImage item;
if (m_ImagePool.Count > 0)
@@ -134,11 +141,12 @@ namespace XericUI.XTable.Rendering.Elements
{
item = CreateImage(name);
}
BindStyle(item.Style, styleNamespace);
m_ActiveImages.Add(item);
return item;
}
public PooledText GetText(string name = "cell_text")
public PooledText GetText(string name = "cell_text", string styleNamespace = null)
{
PooledText item;
if (m_TextPool.Count > 0)
@@ -152,10 +160,32 @@ namespace XericUI.XTable.Rendering.Elements
{
item = CreateText(name);
}
BindStyle(item.Style, styleNamespace);
m_ActiveTexts.Add(item);
return item;
}
/// <summary>运行时绑定样式到池元素的 StyleBoundElement,实现被动更新(push)</summary>
private void BindStyle(StyleBoundElement style, string cellNamespace)
{
if (!Application.isPlaying) return;
string ns = cellNamespace ?? m_DefaultStyleNamespace;
if (string.IsNullOrEmpty(ns)) return;
if (style != null && style.BoundNamespace != ns)
{
style.OnStyleChangedCallback -= OnStyleChangedNotify;
style.OnStyleChangedCallback += OnStyleChangedNotify;
style.Bind(ns);
}
}
private void OnStyleChangedNotify()
{
OnStyleChangeDetected?.Invoke();
}
public void ReturnAll()
{
foreach (var img in m_ActiveImages) ReturnImage(img);
@@ -32,12 +32,19 @@ namespace XericUI.XTable.Rendering.Elements
/// <summary>是否已绑定</summary>
private bool m_IsBound;
/// <summary>样式变更时触发(通知表格重绘)</summary>
public event System.Action OnStyleChangedCallback;
/// <summary>当前绑定的命名空间(空字符串表示未绑定)</summary>
public string BoundNamespace => m_IsBound ? (m_StyleNamespace ?? "") : "";
#endregion
#region 公开方法
/// <summary>
/// 绑定到指定命名空间并开始监听样式。
/// 运行时注册 StyleField 实现被动更新(push);编辑器下在渲染时直接 pull。
/// </summary>
public void Bind(string styleNamespace)
{
@@ -46,6 +53,11 @@ namespace XericUI.XTable.Rendering.Elements
if (string.IsNullOrEmpty(styleNamespace)) return;
// 检查命名空间是否存在,避免 Register → GetValue 报错
var namespaces = StyleManager.GetAvailableNamespaces();
if (namespaces == null || !namespaces.Contains(styleNamespace))
return;
// 预注册常用路径
RegisterField("/cell/bg/color", OnStyleChanged);
RegisterField("/cell/fg/color", OnStyleChanged);
@@ -72,7 +84,7 @@ namespace XericUI.XTable.Rendering.Elements
{
if (kvp.Value != null)
{
kvp.Value.OnValueChanged -= OnStyleChanged;
kvp.Value.Member.OnValueChanged -= OnStyleChanged;
kvp.Value.Unregister();
}
}
@@ -125,7 +137,7 @@ namespace XericUI.XTable.Rendering.Elements
StylePath = path
};
field.Register();
field.OnValueChanged += callback;
field.Member.OnValueChanged += callback;
m_Fields[path] = field;
}
@@ -137,6 +149,7 @@ namespace XericUI.XTable.Rendering.Elements
private void OnStyleChanged(StyleValue val)
{
RefreshAll();
OnStyleChangedCallback?.Invoke();
}
#endregion
+18 -18
View File
@@ -6,33 +6,33 @@
namespace: xeric_table_default
// ---- 单元格背景 ----
/cell/bg/color = (1,1,1,1):UnityEngine.Color @Desc:单元格背景颜色
cell/bg/color = (1,1,1,1):UnityEngine.Color @Desc:单元格背景颜色
// ---- 单元格前景 ----
/cell/fg/color = (0.1,0.1,0.1,1):UnityEngine.Color @Desc:单元格前景文字颜色
cell/fg/color = (0.1,0.1,0.1,1):UnityEngine.Color @Desc:单元格前景文字颜色
// ---- 边框 ----
/cell/border/top/color = (0.8,0.8,0.8,1):UnityEngine.Color @Desc:上边框颜色
/cell/border/top/width = 1:System.Single @Desc:上边框宽度
/cell/border/bottom/color = (0.8,0.8,0.8,1):UnityEngine.Color @Desc:下边框颜色
/cell/border/bottom/width = 1:System.Single @Desc:下边框宽度
/cell/border/left/color = (0.8,0.8,0.8,1):UnityEngine.Color @Desc:左边框颜色
/cell/border/left/width = 1:System.Single @Desc:左边框宽度
/cell/border/right/color = (0.8,0.8,0.8,1):UnityEngine.Color @Desc:右边框颜色
/cell/border/right/width = 1:System.Single @Desc:右边框宽度
cell/border/top/color = (0.8,0.8,0.8,1):UnityEngine.Color @Desc:上边框颜色
cell/border/top/width = 1:System.Single @Desc:上边框宽度
cell/border/bottom/color = (0.8,0.8,0.8,1):UnityEngine.Color @Desc:下边框颜色
cell/border/bottom/width = 1:System.Single @Desc:下边框宽度
cell/border/left/color = (0.8,0.8,0.8,1):UnityEngine.Color @Desc:左边框颜色
cell/border/left/width = 1:System.Single @Desc:左边框宽度
cell/border/right/color = (0.8,0.8,0.8,1):UnityEngine.Color @Desc:右边框颜色
cell/border/right/width = 1:System.Single @Desc:右边框宽度
// ---- 选中高亮 ----
/cell/selection/bg/color = (0.2,0.5,1,0.3):UnityEngine.Color @Desc:选中单元格高亮颜色
cell/selection/bg/color = (0.2,0.5,1,0.3):UnityEngine.Color @Desc:选中单元格高亮颜色
// ---- 表头样式 ----
/header/bg/color = (0.9,0.9,0.9,1):UnityEngine.Color @Desc:表头背景颜色
/header/fg/color = (0,0,0,1):UnityEngine.Color @Desc:表头文字颜色
header/bg/color = (0.9,0.9,0.9,1):UnityEngine.Color @Desc:表头背景颜色
header/fg/color = (0,0,0,1):UnityEngine.Color @Desc:表头文字颜色
// ---- 字体 ----
/cell/font/size = 14:System.Int32 @Desc:默认字体大小
/cell/font/alignment = MiddleCenter:UnityEngine.TextAnchor @Desc:默认文本对齐
/cell/font/richText = true:System.Boolean @Desc:是否启用富文本
cell/font/size = 14:System.Int32 @Desc:默认字体大小
cell/font/alignment = MiddleCenter:UnityEngine.TextAnchor @Desc:默认文本对齐
cell/font/richText = true:System.Boolean @Desc:是否启用富文本
// ---- 行高 / 列宽(缺省值) ----
/cell/default/height = 40:System.Single @Desc:默认行高
/cell/default/width = 100:System.Single @Desc:默认列宽
cell/default/height = 40:System.Single @Desc:默认行高
cell/default/width = 100:System.Single @Desc:默认列宽