From 0c89d93ee2c49978a77d25daf2fc94f097fd0215 Mon Sep 17 00:00:00 2001
From: LiRuoChen <571244399@qq.com>
Date: Thu, 9 Jul 2026 19:22:09 +0800
Subject: [PATCH 1/4] =?UTF-8?q?=E5=8D=95=E5=85=83=E6=A0=BC=E5=86=85?=
=?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=A0=B7=E5=BC=8F=E5=B1=9E=E6=80=A7=E5=AD=97?=
=?UTF-8?q?=E6=AE=B5=EF=BC=8C=E4=BB=A5=E5=8F=8A=E5=86=85=E5=AE=B9=E7=B1=BB?=
=?UTF-8?q?=E5=9E=8B=E5=88=87=E6=8D=A2=E7=9A=84=E5=8A=9F=E8=83=BD=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Editor/XTable/XericUIActionTableEditor.cs | 94 +++--
Runtime/XTable/Core/XTableCellData.cs | 107 ++++--
.../Rendering/Component/TableRenderer.cs | 133 ++++---
.../Rendering/Component/XericUIActionTable.cs | 326 +++++++++++++-----
4 files changed, 466 insertions(+), 194 deletions(-)
diff --git a/Editor/XTable/XericUIActionTableEditor.cs b/Editor/XTable/XericUIActionTableEditor.cs
index af00346..b816a65 100644
--- a/Editor/XTable/XericUIActionTableEditor.cs
+++ b/Editor/XTable/XericUIActionTableEditor.cs
@@ -2,6 +2,7 @@ using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
using XericLibrary.Runtime.MacroLibrary;
+using XericLibrary.Runtime.SuperStyleSheet;
using XericUI.XTable.Core;
using XericUI.XTable.Rendering.Component;
@@ -177,9 +178,9 @@ namespace XericUIEditor.XTable
if (GUILayout.Button("手动刷新视图", GUILayout.Height(22)))
EditorApplication.delayCall += () => m_Table.RefreshView();
- // ── 预制体配置 ──
+ // ── 单元格配置 ──
EditorGUILayout.Space(4);
- EditorGUILayout.LabelField("单元格预制体配置", EditorStyles.boldLabel);
+ EditorGUILayout.LabelField("单元格配置", EditorStyles.boldLabel);
int selRow = m_Table.SelectedRow;
int selCol = m_Table.SelectedCol;
if (selRow < 0 || selCol < 0)
@@ -189,30 +190,79 @@ namespace XericUIEditor.XTable
else
{
var data = m_Table.TableData?.GetCell(selRow, selCol);
- GameObject currentPrefab = data?.Prefab;
- EditorGUI.BeginDisabledGroup(true);
- EditorGUILayout.TextField("目标单元格", $"({selRow}, {selCol})");
- EditorGUI.EndDisabledGroup();
-
- GameObject newPrefab = (GameObject)EditorGUILayout.ObjectField(
- "预制体", currentPrefab, typeof(GameObject), false);
-
- EditorGUILayout.BeginHorizontal();
- if (GUILayout.Button("应用预制体", GUILayout.Height(22)))
+ if (data == null)
{
- Undo.RecordObject(m_Table, "Set Cell Prefab");
- m_Table.SetCellPrefab(selRow, selCol, newPrefab);
- EditorUtility.SetDirty(m_Table);
- Repaint();
+ EditorGUILayout.HelpBox("单元格数据为空", MessageType.Warning);
}
- if (GUILayout.Button("清除预制体", GUILayout.Height(22)))
+ else
{
- Undo.RecordObject(m_Table, "Clear Cell Prefab");
- m_Table.ClearCellPrefab(selRow, selCol);
- EditorUtility.SetDirty(m_Table);
- Repaint();
+ EditorGUI.BeginDisabledGroup(true);
+ EditorGUILayout.TextField("目标单元格", $"({selRow}, {selCol})");
+ EditorGUI.EndDisabledGroup();
+
+ EditorGUI.BeginChangeCheck();
+
+ // 内容类型
+ CellContentType ct = (CellContentType)EditorGUILayout.EnumPopup("内容类型", data.ContentType);
+
+ // 根据类型显示对应字段
+ switch (ct)
+ {
+ case CellContentType.Text:
+ EditorGUILayout.LabelField("文本内容", data.Text ?? "(空)");
+ break;
+ case CellContentType.Image:
+ EditorGUILayout.ObjectField("图片纹理", data.Image, typeof(Texture2D), false);
+ break;
+ case CellContentType.Prefab:
+ GameObject newPrefab = (GameObject)EditorGUILayout.ObjectField(
+ "预制体", data.Prefab, typeof(GameObject), false);
+ if (EditorGUI.EndChangeCheck())
+ {
+ Undo.RecordObject(m_Table, "Set Cell Prefab");
+ data.Prefab = newPrefab;
+ data.ContentType = ct;
+ m_Table.SetCellPrefab(selRow, selCol, newPrefab);
+ EditorUtility.SetDirty(m_Table);
+ Repaint();
+ }
+ goto skipEndChangeCheck;
+ }
+ // 默认 Text 类型
+ string newText = EditorGUILayout.TextField("文本内容", data.Text ?? "");
+ if (EditorGUI.EndChangeCheck())
+ {
+ Undo.RecordObject(m_Table, "Edit Cell");
+ data.Text = newText;
+ data.ContentType = ct;
+ EditorUtility.SetDirty(m_Table);
+ m_Table.MarkDirty(TableDirtyType.DataChanged);
+ EditorUtility.SetDirty(m_Table);
+ Repaint();
+ }
+ skipEndChangeCheck:
+ ;
+
+ // 样式
+ EditorGUILayout.Space(2);
+ EditorGUILayout.LabelField("单元格样式 (StyleMember)", EditorStyles.miniBoldLabel);
+ EditorGUI.BeginChangeCheck();
+ string ns = EditorGUILayout.TextField("命名空间",
+ data.CellStyle?.CurrentNamespace ?? "");
+ string path = EditorGUILayout.TextField("样式路径",
+ data.CellStyle?.StylePath ?? "");
+ if (EditorGUI.EndChangeCheck())
+ {
+ Undo.RecordObject(m_Table, "Edit Cell Style");
+ if (data.CellStyle == null)
+ data.CellStyle = new StyleMember();
+ data.CellStyle.CurrentNamespace = ns;
+ data.CellStyle.StylePath = path;
+ EditorUtility.SetDirty(m_Table);
+ m_Table.MarkDirty(TableDirtyType.DataChanged);
+ Repaint();
+ }
}
- EditorGUILayout.EndHorizontal();
}
EditorGUI.indentLevel--;
diff --git a/Runtime/XTable/Core/XTableCellData.cs b/Runtime/XTable/Core/XTableCellData.cs
index a5257fb..e4a3614 100644
--- a/Runtime/XTable/Core/XTableCellData.cs
+++ b/Runtime/XTable/Core/XTableCellData.cs
@@ -1,53 +1,84 @@
using System;
using UnityEngine;
+using XericLibrary.Runtime.SuperStyleSheet;
namespace XericUI.XTable.Core
{
- ///
- /// 单元格数据模型——仅保存数据内容,不保存自身尺寸。
- /// 尺寸由渲染阶段的行列标题(行高/列宽)决定。
- /// 样式通过 StyleNamespace 字符串引用 StyleManager 中的命名空间。
- ///
- [Serializable]
- public class XTableCellData
- {
- /// 文本内容
- public string Text;
+ /// 单元格内容类型——决定渲染时使用哪种内容
+ public enum CellContentType
+ {
+ /// 文本内容
+ Text,
+ /// 图片纹理
+ Image,
+ /// 预制体实例
+ Prefab,
+ }
- /// 图片纹理
- public Texture2D Image;
+ ///
+ /// 单元格数据模型——仅保存数据内容,不保存自身尺寸。
+ /// 尺寸由渲染阶段的行列标题(行高/列宽)决定。
+ /// 样式通过 StyleNamespace 字符串引用 StyleManager 中的命名空间。
+ ///
+ [Serializable]
+ public class XTableCellData
+ {
+ /// 内容类型——决定渲染时使用 Text / Image / Prefab 中的哪一个
+ public CellContentType ContentType;
- /// 预制体对象(用于嵌入复杂 UI 元素)
- public GameObject Prefab;
+ /// 文本内容(ContentType == Text 时生效)
+ public string Text;
- ///
- /// 样式命名空间——对应 StyleManager 中的命名空间。
- /// 为空或 "xeric_table_default" 时使用默认表格样式。
- /// 渲染时从此命名空间读取 /cell/bg/color、/cell/font/size 等路径。
- ///
- public string StyleNamespace;
+ /// 图片纹理(ContentType == Image 时生效)
+ public Texture2D Image;
- /// 预制体实例从对象池取出时回调——外部可在此初始化实例内容
- [NonSerialized] public System.Action OnPrefabAcquire;
+ /// 预制体对象(ContentType == Prefab 时生效,用于嵌入复杂 UI 元素)
+ public GameObject Prefab;
- /// 预制体实例归还对象池前回调——外部可在此清理引用
- [NonSerialized] public System.Action OnPrefabRelease;
+ ///
+ /// 样式命名空间——对应 StyleManager 中的命名空间。
+ /// 为空或 "xeric_table_default" 时使用默认表格样式。
+ /// 渲染时从此命名空间读取 /cell/bg/color、/cell/font/size 等路径。
+ ///
+ public string StyleNamespace;
- public XTableCellData()
- { }
+ ///
+ /// 单元格级别样式覆盖——通过命名空间 + 路径引用样式表中的值。
+ /// 渲染时优先使用此样式路径派生颜色/尺寸(如 {StylePath}/bg/color),未设置时回退到 StyleNamespace。
+ ///
+ public StyleMember CellStyle;
- public XTableCellData(string text) => Text = text;
+ /// 预制体实例从对象池取出时回调——外部可在此初始化实例内容
+ [NonSerialized] public System.Action OnPrefabAcquire;
- public XTableCellData(string text, string styleNamespace = null) : this(text) =>
- StyleNamespace = styleNamespace;
+ /// 预制体实例归还对象池前回调——外部可在此清理引用
+ [NonSerialized] public System.Action OnPrefabRelease;
- public XTableCellData(string text, Texture2D image, string styleNamespace = null) :
- this(text, styleNamespace) => Image = image;
+ public XTableCellData()
+ { }
- public void ClearEvent()
- {
- OnPrefabAcquire = null;
- OnPrefabRelease = null;
- }
- }
-}
\ No newline at end of file
+ public XTableCellData(string text) => Text = text;
+
+ public XTableCellData(string text, string styleNamespace = null) : this(text) =>
+ StyleNamespace = styleNamespace;
+
+ public XTableCellData(string text, Texture2D image, string styleNamespace = null) :
+ this(text, styleNamespace) => Image = image;
+
+ /// 获取该单元格渲染时使用的样式命名空间(CellStyle 优先,否则 fallback 到 StyleNamespace)
+ public string GetEffectiveStyleNamespace(string fallbackNamespace)
+ {
+ if (CellStyle != null && !string.IsNullOrEmpty(CellStyle.CurrentNamespace))
+ return CellStyle.CurrentNamespace;
+ if (!string.IsNullOrEmpty(StyleNamespace))
+ return StyleNamespace;
+ return fallbackNamespace;
+ }
+
+ public void ClearEvent()
+ {
+ OnPrefabAcquire = null;
+ OnPrefabRelease = null;
+ }
+ }
+}
diff --git a/Runtime/XTable/Rendering/Component/TableRenderer.cs b/Runtime/XTable/Rendering/Component/TableRenderer.cs
index 35a7c03..6f7760d 100644
--- a/Runtime/XTable/Rendering/Component/TableRenderer.cs
+++ b/Runtime/XTable/Rendering/Component/TableRenderer.cs
@@ -26,6 +26,9 @@ namespace XericUI.XTable.Rendering.Component
/// 共享活跃预制体映射表(由 XericUIActionTable 传入)
public Dictionary<(int, int), GameObject> ActivePrefabMap;
+ /// Texture2D → Sprite 缓存,避免每帧分配
+ private Dictionary m_SpriteCache;
+
#endregion
#region 公开属性
@@ -249,30 +252,46 @@ namespace XericUI.XTable.Rendering.Component
if (data == null) continue;
- if (!string.IsNullOrEmpty(data.Text))
+ switch (data.ContentType)
{
- 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, XericUIActionTable.STYLE_CELL_FG_COLOR,
- XericUIActionTable.FG_COLOR_FALLBACK);
- txt.Text.fontSize = GetStyleInt(cellNS, XericUIActionTable.STYLE_CELL_FONT_SIZE,
- XericUIActionTable.FONT_SIZE_FALLBACK);
- txt.Text.alignment = TextAlignmentOptions.Midline;
- txt.Text.font = GetStyleFontAsset?.Invoke(cellNS,
- XericUIActionTable.STYLE_CELL_FONT_ASSET) ?? txt.Text.font;
- }
-
- if (data.Prefab != null && PrefabPool != null)
- {
- GameObject instance = PrefabPool.Acquire(data.Prefab, r, c);
- RectTransform prt = instance.GetComponent();
- prt.anchoredPosition = new Vector2(cellX, cellY);
- prt.sizeDelta = new Vector2(cellW, cellH);
- if (ActivePrefabMap != null)
- ActivePrefabMap[(r, c)] = instance;
- data.OnPrefabAcquire?.Invoke(instance);
+ case CellContentType.Text:
+ 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, XericUIActionTable.STYLE_CELL_FG_COLOR,
+ XericUIActionTable.FG_COLOR_FALLBACK);
+ txt.Text.fontSize = GetStyleInt(cellNS, XericUIActionTable.STYLE_CELL_FONT_SIZE,
+ XericUIActionTable.FONT_SIZE_FALLBACK);
+ txt.Text.alignment = TextAlignmentOptions.Midline;
+ txt.Text.font = GetStyleFontAsset?.Invoke(cellNS,
+ XericUIActionTable.STYLE_CELL_FONT_ASSET) ?? txt.Text.font;
+ }
+ break;
+ case CellContentType.Image:
+ if (data.Image != null)
+ {
+ Sprite sprite = GetOrCreateSprite(data.Image);
+ var img = m_Assembler.GetImage("cell_image", cellNS);
+ img.Rect.anchoredPosition = new Vector2(cellX + 4, cellY);
+ img.Rect.sizeDelta = new Vector2(cellW - 8, cellH);
+ img.Image.sprite = sprite;
+ }
+ break;
+ case CellContentType.Prefab:
+ if (data.Prefab != null && PrefabPool != null)
+ {
+ GameObject instance = PrefabPool.Acquire(data.Prefab, r, c);
+ RectTransform prt = instance.GetComponent();
+ prt.anchoredPosition = new Vector2(cellX, cellY);
+ prt.sizeDelta = new Vector2(cellW, cellH);
+ if (ActivePrefabMap != null)
+ ActivePrefabMap[(r, c)] = instance;
+ data.OnPrefabAcquire?.Invoke(instance);
+ }
+ break;
}
}
}
@@ -338,23 +357,39 @@ namespace XericUI.XTable.Rendering.Component
if (data == null) continue;
- if (!string.IsNullOrEmpty(data.Text))
+ switch (data.ContentType)
{
- 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;
- }
-
- if (data.Prefab != null && PrefabPool != null)
- {
- GameObject instance = PrefabPool.Acquire(data.Prefab, r, c);
- RectTransform prt = instance.GetComponent();
- prt.anchoredPosition = new Vector2(cellX, cellY);
- prt.sizeDelta = new Vector2(cellW, cellH);
- if (ActivePrefabMap != null)
- ActivePrefabMap[(r, c)] = instance;
- data.OnPrefabAcquire?.Invoke(instance);
+ case CellContentType.Text:
+ 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;
+ }
+ break;
+ case CellContentType.Image:
+ if (data.Image != null)
+ {
+ Sprite sprite = GetOrCreateSprite(data.Image);
+ var img = m_Assembler.GetImage("cell_image", cellNS);
+ img.Rect.anchoredPosition = new Vector2(cellX + 4, cellY);
+ img.Rect.sizeDelta = new Vector2(cellW - 8, cellH);
+ img.Image.sprite = sprite;
+ }
+ break;
+ case CellContentType.Prefab:
+ if (data.Prefab != null && PrefabPool != null)
+ {
+ GameObject instance = PrefabPool.Acquire(data.Prefab, r, c);
+ RectTransform prt = instance.GetComponent();
+ prt.anchoredPosition = new Vector2(cellX, cellY);
+ prt.sizeDelta = new Vector2(cellW, cellH);
+ if (ActivePrefabMap != null)
+ ActivePrefabMap[(r, c)] = instance;
+ data.OnPrefabAcquire?.Invoke(instance);
+ }
+ break;
}
}
}
@@ -362,6 +397,26 @@ namespace XericUI.XTable.Rendering.Component
#endregion
+ #region 辅助方法
+
+ /// 将 Texture2D 转为 Sprite(带缓存),用于 Image 类型单元格渲染
+ private Sprite GetOrCreateSprite(Texture2D texture)
+ {
+ if (texture == null) return null;
+
+ if (m_SpriteCache == null)
+ m_SpriteCache = new Dictionary();
+
+ if (!m_SpriteCache.TryGetValue(texture, out Sprite sprite))
+ {
+ sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
+ m_SpriteCache[texture] = sprite;
+ }
+ return sprite;
+ }
+
+ #endregion
+
#region 坐标计算
private float CalcRowTopY(int row, float[] rowHeights)
diff --git a/Runtime/XTable/Rendering/Component/XericUIActionTable.cs b/Runtime/XTable/Rendering/Component/XericUIActionTable.cs
index 8940bac..87c3883 100644
--- a/Runtime/XTable/Rendering/Component/XericUIActionTable.cs
+++ b/Runtime/XTable/Rendering/Component/XericUIActionTable.cs
@@ -76,6 +76,9 @@ namespace XericUI.XTable.Rendering.Component
/// 活跃预制体实例映射 (row, col) → instance,用于回调编排
[System.NonSerialized] private Dictionary<(int, int), GameObject> m_ActivePrefabMap;
+ /// Texture2D → Sprite 缓存,避免每帧 Sprite.Create 分配
+ [System.NonSerialized] private Dictionary m_SpriteCache;
+
/// 表格四叉树——按 StyleNamespace 分区,渲染阶段查询可见象限
[System.NonSerialized] private XTableQuadtree m_Quadtree;
@@ -250,26 +253,42 @@ namespace XericUI.XTable.Rendering.Component
if (data == null) continue;
- if (!string.IsNullOrEmpty(data.Text))
+ switch (data.ContentType)
{
- 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 = GetCellFgColor(cellNS);
- txt.Text.fontSize = GetCellFontSize(cellNS);
- txt.Text.alignment = TextAlignmentOptions.Midline;
- txt.Text.font = GetCellFontAsset(cellNS) ?? txt.Text.font;
- }
-
- if (data.Prefab != null)
- {
- GameObject instance = m_PrefabPool.Acquire(data.Prefab, row, col);
- RectTransform prt = instance.GetComponent();
- prt.anchoredPosition = new Vector2(cellX, cellY);
- prt.sizeDelta = new Vector2(cellW, cellH);
- m_ActivePrefabMap[(row, col)] = instance;
- data.OnPrefabAcquire?.Invoke(instance);
+ case CellContentType.Text:
+ 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 = GetCellFgColor(cellNS);
+ txt.Text.fontSize = GetCellFontSize(cellNS);
+ txt.Text.alignment = TextAlignmentOptions.Midline;
+ txt.Text.font = GetCellFontAsset(cellNS) ?? txt.Text.font;
+ }
+ break;
+ case CellContentType.Image:
+ if (data.Image != null)
+ {
+ Sprite sprite = GetOrCreateSprite(data.Image);
+ var img = m_Assembler.GetImage("cell_image", cellNS);
+ img.Rect.anchoredPosition = new Vector2(cellX + 4, cellY);
+ img.Rect.sizeDelta = new Vector2(cellW - 8, cellH);
+ img.Image.sprite = sprite;
+ }
+ break;
+ case CellContentType.Prefab:
+ if (data.Prefab != null)
+ {
+ GameObject instance = m_PrefabPool.Acquire(data.Prefab, row, col);
+ RectTransform prt = instance.GetComponent();
+ prt.anchoredPosition = new Vector2(cellX, cellY);
+ prt.sizeDelta = new Vector2(cellW, cellH);
+ m_ActivePrefabMap[(row, col)] = instance;
+ data.OnPrefabAcquire?.Invoke(instance);
+ }
+ break;
}
}
}
@@ -333,22 +352,38 @@ namespace XericUI.XTable.Rendering.Component
if (data == null) continue;
- if (!string.IsNullOrEmpty(data.Text))
+ switch (data.ContentType)
{
- 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;
- }
-
- if (data.Prefab != null)
- {
- GameObject instance = m_PrefabPool.Acquire(data.Prefab, row, col);
- RectTransform prt = instance.GetComponent();
- prt.anchoredPosition = new Vector2(cellX, cellY);
- prt.sizeDelta = new Vector2(cellW, cellH);
- m_ActivePrefabMap[(row, col)] = instance;
- data.OnPrefabAcquire?.Invoke(instance);
+ case CellContentType.Text:
+ 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;
+ }
+ break;
+ case CellContentType.Image:
+ if (data.Image != null)
+ {
+ Sprite sprite = GetOrCreateSprite(data.Image);
+ var img = m_Assembler.GetImage("cell_image", cellNS);
+ img.Rect.anchoredPosition = new Vector2(cellX + 4, cellY);
+ img.Rect.sizeDelta = new Vector2(cellW - 8, cellH);
+ img.Image.sprite = sprite;
+ }
+ break;
+ case CellContentType.Prefab:
+ if (data.Prefab != null)
+ {
+ GameObject instance = m_PrefabPool.Acquire(data.Prefab, row, col);
+ RectTransform prt = instance.GetComponent();
+ prt.anchoredPosition = new Vector2(cellX, cellY);
+ prt.sizeDelta = new Vector2(cellW, cellH);
+ m_ActivePrefabMap[(row, col)] = instance;
+ data.OnPrefabAcquire?.Invoke(instance);
+ }
+ break;
}
}
}
@@ -517,38 +552,49 @@ namespace XericUI.XTable.Rendering.Component
MarkDirty(TableDirtyType.DataChanged);
}
+ /// 设置文本内容(ContentType 自动设为 Text)
public XTableCellData SetCellText(int row, int col, string text)
{
var data = TableData.GetOrCreateCell(row, col);
data.Text = text;
+ data.ContentType = CellContentType.Text;
MarkDirty(TableDirtyType.DataChanged);
return data;
}
- public XTableCellData GetCellData(int row, int col)
- => TableData.GetOrCreateCell(row, col);
-
- /// 为指定单元格设置预制体
- public XTableCellData SetCellPrefab(int row, int col, GameObject prefab)
- {
- var data = TableData.GetOrCreateCell(row, col);
- data.Prefab = prefab;
- MarkDirty(TableDirtyType.DataChanged);
+ /// 设置图片纹理(ContentType 自动设为 Image)
+ public XTableCellData SetCellImage(int row, int col, Texture2D image)
+ {
+ var data = TableData.GetOrCreateCell(row, col);
+ data.Image = image;
+ data.ContentType = CellContentType.Image;
+ MarkDirty(TableDirtyType.DataChanged);
return data;
- }
+ }
- /// 清除指定单元格的预制体
- public void ClearCellPrefab(int row, int col)
- {
- var data = TableData.GetCell(row, col);
- if (data == null) return;
- data.Prefab = null;
- data.OnPrefabAcquire = null;
- data.OnPrefabRelease = null;
- MarkDirty(TableDirtyType.DataChanged);
- }
+ /// 设置预制体(ContentType 自动设为 Prefab)
+ public XTableCellData SetCellPrefab(int row, int col, GameObject prefab)
+ {
+ var data = TableData.GetOrCreateCell(row, col);
+ data.Prefab = prefab;
+ data.ContentType = CellContentType.Prefab;
+ MarkDirty(TableDirtyType.DataChanged);
+ return data;
+ }
- /// 设置单元格的样式命名空间
+ /// 设置单元格样式覆盖(StyleMember:命名空间 + 路径)
+ public XTableCellData SetCellStyle(int row, int col, string styleNamespace, string stylePath)
+ {
+ var data = TableData.GetOrCreateCell(row, col);
+ if (data.CellStyle == null)
+ data.CellStyle = new XericLibrary.Runtime.SuperStyleSheet.StyleMember();
+ data.CellStyle.CurrentNamespace = styleNamespace ?? "";
+ data.CellStyle.StylePath = stylePath ?? "";
+ MarkDirty(TableDirtyType.StyleChanged);
+ return data;
+ }
+
+ /// 设置单元格的样式命名空间(兼容旧版,等同于 StyleNamespace 字段)
public void SetCellStyleNamespace(int row, int col, string styleNamespace)
{
var data = TableData.GetOrCreateCell(row, col);
@@ -556,10 +602,54 @@ namespace XericUI.XTable.Rendering.Component
MarkDirty(TableDirtyType.StyleChanged);
}
- /// 获取单元格的样式命名空间
+ /// 清除文本内容
+ public void ClearCellText(int row, int col)
+ {
+ var data = TableData.GetCell(row, col);
+ if (data == null) return;
+ data.Text = null;
+ if (data.ContentType == CellContentType.Text)
+ data.ContentType = CellContentType.Text; // 保持类型不变,仅清空内容
+ MarkDirty(TableDirtyType.DataChanged);
+ }
+
+ /// 清除图片纹理
+ public void ClearCellImage(int row, int col)
+ {
+ var data = TableData.GetCell(row, col);
+ if (data == null) return;
+ data.Image = null;
+ MarkDirty(TableDirtyType.DataChanged);
+ }
+
+ /// 清除预制体及委托
+ public void ClearCellPrefab(int row, int col)
+ {
+ var data = TableData.GetCell(row, col);
+ if (data == null) return;
+ data.Prefab = null;
+ data.OnPrefabAcquire = null;
+ data.OnPrefabRelease = null;
+ MarkDirty(TableDirtyType.DataChanged);
+ }
+
+ /// 清除单元格样式覆盖
+ public void ClearCellStyle(int row, int col)
+ {
+ var data = TableData.GetCell(row, col);
+ if (data == null) return;
+ data.CellStyle = null;
+ MarkDirty(TableDirtyType.StyleChanged);
+ }
+
+ public XTableCellData GetCellData(int row, int col)
+ => TableData.GetOrCreateCell(row, col);
+
+ /// 获取单元格的样式命名空间(含回退逻辑)
public string GetCellStyleNamespace(int row, int col)
{
- return TableData.GetCell(row, col)?.StyleNamespace ?? m_DefaultStyleNamespace;
+ var data = TableData.GetCell(row, col);
+ return data != null ? data.GetEffectiveStyleNamespace(m_DefaultStyleNamespace) : m_DefaultStyleNamespace;
}
public void MergeCells(int startRow, int startCol, int rowSpan, int colSpan)
@@ -1201,27 +1291,42 @@ namespace XericUI.XTable.Rendering.Component
if (data == null) continue;
- if (!string.IsNullOrEmpty(data.Text))
+ switch (data.ContentType)
{
- 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 = GetCellFgColor(cellNS);
- txt.Text.fontSize = GetCellFontSize(cellNS);
- txt.Text.alignment = TextAlignmentOptions.Midline;
- txt.Text.font = GetCellFontAsset(cellNS) ?? txt.Text.font;
- }
-
- // 预制体渲染
- if (data.Prefab != null)
- {
- GameObject instance = m_PrefabPool.Acquire(data.Prefab, r, c);
- RectTransform prt = instance.GetComponent();
- prt.anchoredPosition = new Vector2(cellX, cellY);
- prt.sizeDelta = new Vector2(cellW, cellH);
- m_ActivePrefabMap[(r, c)] = instance;
- data.OnPrefabAcquire?.Invoke(instance);
+ case CellContentType.Text:
+ 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 = GetCellFgColor(cellNS);
+ txt.Text.fontSize = GetCellFontSize(cellNS);
+ txt.Text.alignment = TextAlignmentOptions.Midline;
+ txt.Text.font = GetCellFontAsset(cellNS) ?? txt.Text.font;
+ }
+ break;
+ case CellContentType.Image:
+ if (data.Image != null)
+ {
+ Sprite sprite = GetOrCreateSprite(data.Image);
+ var img = m_Assembler.GetImage("cell_image", cellNS);
+ img.Rect.anchoredPosition = new Vector2(cellX + 4, cellY);
+ img.Rect.sizeDelta = new Vector2(cellW - 8, cellH);
+ img.Image.sprite = sprite;
+ }
+ break;
+ case CellContentType.Prefab:
+ if (data.Prefab != null)
+ {
+ GameObject instance = m_PrefabPool.Acquire(data.Prefab, r, c);
+ RectTransform prt = instance.GetComponent();
+ prt.anchoredPosition = new Vector2(cellX, cellY);
+ prt.sizeDelta = new Vector2(cellW, cellH);
+ m_ActivePrefabMap[(r, c)] = instance;
+ data.OnPrefabAcquire?.Invoke(instance);
+ }
+ break;
}
}
}
@@ -1287,24 +1392,39 @@ namespace XericUI.XTable.Rendering.Component
if (data == null) continue;
- if (!string.IsNullOrEmpty(data.Text))
+ switch (data.ContentType)
{
- 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;
- // 运行时样式由 StyleBoundElement 被动更新,此处仅设置文本内容
- }
-
- // 预制体渲染
- if (data.Prefab != null)
- {
- GameObject instance = m_PrefabPool.Acquire(data.Prefab, r, c);
- RectTransform prt = instance.GetComponent();
- prt.anchoredPosition = new Vector2(cellX, cellY);
- prt.sizeDelta = new Vector2(cellW, cellH);
- m_ActivePrefabMap[(r, c)] = instance;
- data.OnPrefabAcquire?.Invoke(instance);
+ case CellContentType.Text:
+ 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;
+ // 运行时样式由 StyleBoundElement 被动更新,此处仅设置文本内容
+ }
+ break;
+ case CellContentType.Image:
+ if (data.Image != null)
+ {
+ Sprite sprite = GetOrCreateSprite(data.Image);
+ var img = m_Assembler.GetImage("cell_image", cellNS);
+ img.Rect.anchoredPosition = new Vector2(cellX + 4, cellY);
+ img.Rect.sizeDelta = new Vector2(cellW - 8, cellH);
+ img.Image.sprite = sprite;
+ }
+ break;
+ case CellContentType.Prefab:
+ if (data.Prefab != null)
+ {
+ GameObject instance = m_PrefabPool.Acquire(data.Prefab, r, c);
+ RectTransform prt = instance.GetComponent();
+ prt.anchoredPosition = new Vector2(cellX, cellY);
+ prt.sizeDelta = new Vector2(cellW, cellH);
+ m_ActivePrefabMap[(r, c)] = instance;
+ data.OnPrefabAcquire?.Invoke(instance);
+ }
+ break;
}
}
}
@@ -1330,6 +1450,22 @@ namespace XericUI.XTable.Rendering.Component
return x;
}
+ /// 将 Texture2D 转为 Sprite(带缓存),用于 Image 类型单元格渲染
+ private Sprite GetOrCreateSprite(Texture2D texture)
+ {
+ if (texture == null) return null;
+
+ if (m_SpriteCache == null)
+ m_SpriteCache = new Dictionary();
+
+ if (!m_SpriteCache.TryGetValue(texture, out Sprite sprite))
+ {
+ sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
+ m_SpriteCache[texture] = sprite;
+ }
+ return sprite;
+ }
+
private void RecalculateTotalSize()
{
m_TotalWidth = 0;
@@ -1466,7 +1602,7 @@ namespace XericUI.XTable.Rendering.Component
#region 其他
- private void MarkDirty(TableDirtyType type)
+ public void MarkDirty(TableDirtyType type)
{
m_DirtyFlag.Mark(type);
From 8d3cf4348a5b8c7b7738d4ef2e945c200480a702 Mon Sep 17 00:00:00 2001
From: LiRuoChen <571244399@qq.com>
Date: Fri, 10 Jul 2026 08:36:25 +0800
Subject: [PATCH 2/4] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A1=A8=E6=A0=BC?=
=?UTF-8?q?=E6=AF=8F=E6=AC=A1=E9=80=89=E4=B8=AD=E5=8D=95=E5=85=83=E6=A0=BC?=
=?UTF-8?q?=E4=BC=9A=E5=AF=BC=E8=87=B4=E7=BA=BF=E6=A1=86=E5=88=87=E6=8D=A2?=
=?UTF-8?q?=E4=B8=80=E6=AC=A1=E6=B8=B2=E6=9F=93=E7=8A=B6=E6=80=81=E7=9A=84?=
=?UTF-8?q?=E9=97=AE=E9=A2=98=E3=80=82=20=E4=BF=AE=E5=A4=8D=E8=A1=A8?=
=?UTF-8?q?=E6=A0=BC=E7=A7=BB=E5=8A=A8=E8=B6=85=E8=BF=87=E4=B8=89=E4=B8=AA?=
=?UTF-8?q?=E5=8D=95=E5=85=83=E6=A0=BC=E4=BC=9A=E7=AA=81=E7=84=B6=E5=85=A8?=
=?UTF-8?q?=E9=83=A8=E9=9A=90=E8=97=8F=E7=9A=84=E9=97=AE=E9=A2=98=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Rendering/Component/XericUIActionTable.cs | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/Runtime/XTable/Rendering/Component/XericUIActionTable.cs b/Runtime/XTable/Rendering/Component/XericUIActionTable.cs
index 87c3883..cfc3f97 100644
--- a/Runtime/XTable/Rendering/Component/XericUIActionTable.cs
+++ b/Runtime/XTable/Rendering/Component/XericUIActionTable.cs
@@ -215,6 +215,8 @@ namespace XericUI.XTable.Rendering.Component
{
// 跳过被合并覆盖的单元格
if (TableData.IsCellMerged(row, col)) continue;
+ // 跳过不可见的单元格
+ if (!IsCellVisible(row, col)) continue;
float cellX = GetColLeftX(col);
float cellY = -GetRowTopY(row);
@@ -315,6 +317,8 @@ namespace XericUI.XTable.Rendering.Component
{
// 跳过被合并覆盖的单元格
if (TableData.IsCellMerged(row, col)) continue;
+ // 跳过不可见的单元格
+ if (!IsCellVisible(row, col)) continue;
float cellX = GetColLeftX(col);
float cellY = -GetRowTopY(row);
@@ -932,6 +936,11 @@ namespace XericUI.XTable.Rendering.Component
RecalculateTotalSize();
UpdateVisibleRect();
+ // 确保 ScrollRect Content 尺寸正确(否则滚动时可能裁剪掉全部内容)
+ RectTransform ctRt = ContentTransform as RectTransform;
+ if (ctRt != null)
+ ctRt.sizeDelta = new Vector2(m_TotalWidth, m_TotalHeight);
+
// 更新背景尺寸
if (m_BackgroundGo != null)
{
@@ -960,12 +969,14 @@ namespace XericUI.XTable.Rendering.Component
Transform poolRoot = m_Assembler.PoolRoot;
Transform prefabPoolRoot = m_PrefabPool?.PoolRoot;
Transform contentT = ContentTransform;
+ Transform borderT = contentT.Find("_TableBorders");
for (int i = contentT.childCount - 1; i >= 0; i--)
{
var child = contentT.GetChild(i);
if (poolRoot != null && child == poolRoot) continue;
if (prefabPoolRoot != null && child == prefabPoolRoot) continue;
if (m_BackgroundGo != null && child.gameObject == m_BackgroundGo) continue;
+ if (borderT != null && child == borderT) continue;
child.gameObject.hideFlags = HideFlags.None;
if (Application.isPlaying)
@@ -1434,6 +1445,18 @@ namespace XericUI.XTable.Rendering.Component
#region 坐标计算
+ /// 判断指定单元格是否与当前可见矩形有重叠(用于 RenderQuadrants 裁剪)
+ private bool IsCellVisible(int row, int col)
+ {
+ float cellTop = GetRowTopY(row);
+ float cellBottom = cellTop + m_RowHeights[row];
+ float cellLeft = GetColLeftX(col);
+ float cellRight = cellLeft + m_ColWidths[col];
+
+ return cellBottom > m_VisibleRect.y && cellTop < m_VisibleRect.yMax &&
+ cellRight > m_VisibleRect.x && cellLeft < m_VisibleRect.xMax;
+ }
+
private float GetRowTopY(int row)
{
float y = 0;
From 76d0dfbcb4f15f22ad00e5f99109f1e30beb15a3 Mon Sep 17 00:00:00 2001
From: LiRuoChen <571244399@qq.com>
Date: Fri, 10 Jul 2026 10:59:37 +0800
Subject: [PATCH 3/4] =?UTF-8?q?=E6=8A=8A=E6=A0=B7=E5=BC=8F=E6=96=87?=
=?UTF-8?q?=E4=BB=B6=E9=83=BD=E6=94=BE=E5=88=B0resources=E4=B8=8B=EF=BC=8C?=
=?UTF-8?q?=E7=84=B6=E5=90=8E=E8=A1=A5=E5=85=85=E9=85=8D=E7=BD=AE=E6=96=87?=
=?UTF-8?q?=E4=BB=B6=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Runtime/Resources.meta | 8 ++
Runtime/{XTable => Resources}/Style.meta | 2 +-
.../Style/DefaultTableStyles.xsss | 0
.../Style/DefaultTableStyles.xsss.meta | 0
.../Style}/DefaultXericStyleSheet.xsss | 0
.../Style}/DefaultXericStyleSheet.xsss.meta | 0
Runtime/XTable/Core/XTableConfig.cs | 124 ++++++++++++++++++
Runtime/XTable/Core/XTableConfig.cs.meta | 11 ++
Runtime/XTable/Core/XTableQuadtree.cs | 31 +++--
.../Rendering/Component/TableRenderer.cs | 43 +++---
.../Rendering/Component/XericUIActionTable.cs | 120 ++++++++++-------
11 files changed, 264 insertions(+), 75 deletions(-)
create mode 100644 Runtime/Resources.meta
rename Runtime/{XTable => Resources}/Style.meta (77%)
rename Runtime/{XTable => Resources}/Style/DefaultTableStyles.xsss (100%)
rename Runtime/{XTable => Resources}/Style/DefaultTableStyles.xsss.meta (100%)
rename Runtime/{Core/StyleSheetUI => Resources/Style}/DefaultXericStyleSheet.xsss (100%)
rename Runtime/{Core/StyleSheetUI => Resources/Style}/DefaultXericStyleSheet.xsss.meta (100%)
create mode 100644 Runtime/XTable/Core/XTableConfig.cs
create mode 100644 Runtime/XTable/Core/XTableConfig.cs.meta
diff --git a/Runtime/Resources.meta b/Runtime/Resources.meta
new file mode 100644
index 0000000..3de318b
--- /dev/null
+++ b/Runtime/Resources.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f6a0a99a3d243d2429a9ca17b9b35149
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/XTable/Style.meta b/Runtime/Resources/Style.meta
similarity index 77%
rename from Runtime/XTable/Style.meta
rename to Runtime/Resources/Style.meta
index a2485a1..9345f8a 100644
--- a/Runtime/XTable/Style.meta
+++ b/Runtime/Resources/Style.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 64d88208839a5034db31c330796453aa
+guid: 6da8337ecebc7074b9f37bc69feab5c1
folderAsset: yes
DefaultImporter:
externalObjects: {}
diff --git a/Runtime/XTable/Style/DefaultTableStyles.xsss b/Runtime/Resources/Style/DefaultTableStyles.xsss
similarity index 100%
rename from Runtime/XTable/Style/DefaultTableStyles.xsss
rename to Runtime/Resources/Style/DefaultTableStyles.xsss
diff --git a/Runtime/XTable/Style/DefaultTableStyles.xsss.meta b/Runtime/Resources/Style/DefaultTableStyles.xsss.meta
similarity index 100%
rename from Runtime/XTable/Style/DefaultTableStyles.xsss.meta
rename to Runtime/Resources/Style/DefaultTableStyles.xsss.meta
diff --git a/Runtime/Core/StyleSheetUI/DefaultXericStyleSheet.xsss b/Runtime/Resources/Style/DefaultXericStyleSheet.xsss
similarity index 100%
rename from Runtime/Core/StyleSheetUI/DefaultXericStyleSheet.xsss
rename to Runtime/Resources/Style/DefaultXericStyleSheet.xsss
diff --git a/Runtime/Core/StyleSheetUI/DefaultXericStyleSheet.xsss.meta b/Runtime/Resources/Style/DefaultXericStyleSheet.xsss.meta
similarity index 100%
rename from Runtime/Core/StyleSheetUI/DefaultXericStyleSheet.xsss.meta
rename to Runtime/Resources/Style/DefaultXericStyleSheet.xsss.meta
diff --git a/Runtime/XTable/Core/XTableConfig.cs b/Runtime/XTable/Core/XTableConfig.cs
new file mode 100644
index 0000000..ff7efcb
--- /dev/null
+++ b/Runtime/XTable/Core/XTableConfig.cs
@@ -0,0 +1,124 @@
+using UnityEngine;
+
+namespace XericUI.XTable.Core
+{
+ ///
+ /// 表格系统全局配置资源——统一管理布局、样式回退值、运行时颜色等参数。
+ /// 表格组件在 Awake 时自动加载 Resources 中的 "XTableDefaultConfig",
+ /// 或由外部脚本在初始化阶段显式赋值。
+ ///
+ [CreateAssetMenu(fileName = "XTableConfig", menuName = "Xeric UI/Table/Table Config", order = 100)]
+ public class XTableConfig : ScriptableObject
+ {
+ #region 布局
+
+ [Header("布局")]
+ [Tooltip("新增行时的默认行高(像素)")]
+ public float DefaultRowHeight = 40f;
+
+ [Tooltip("新增列时的默认列宽(像素)")]
+ public float DefaultColumnWidth = 100f;
+
+ [Tooltip("单元格内容水平内边距(左右各此值)")]
+ public float CellHorizontalPadding = 4f;
+
+ #endregion
+
+ #region 四叉树
+
+ [Header("四叉树")]
+ [Tooltip("单节点最大单元格数,超过此值强制空间分裂以提升可见性裁剪效率")]
+ public int QuadtreeMaxCellsPerNode = 64;
+
+ #endregion
+
+ #region 对象池
+
+ [Header("对象池")]
+ [Tooltip("通用对象池初始容量")]
+ public int PoolInitialCapacity = 64;
+
+ #endregion
+
+ #region 样式回退值
+
+ [Header("样式回退值(当 StyleManager 中查不到时使用)")]
+ [Tooltip("默认样式命名空间")]
+ public string DefaultStyleNamespace = "xeric_table_default";
+
+ [Tooltip("单元格背景色")]
+ public Color BgColor = new Color(0.18f, 0.18f, 0.18f, 1f);
+
+ [Tooltip("单元格前景色(文字颜色)")]
+ public Color FgColor = new Color(0.05f, 0.05f, 0.05f);
+
+ [Tooltip("编辑器选中色")]
+ public Color SelectionColor = new Color(0.2f, 0.5f, 1f, 0.3f);
+
+ [Tooltip("边框颜色")]
+ public Color BorderColor = new Color(0.35f, 0.35f, 0.35f, 0.5f);
+
+ [Tooltip("边框宽度")]
+ public float BorderWidth = 1f;
+
+ [Tooltip("字体大小")]
+ public int FontSize = 14;
+
+ #endregion
+
+ #region 运行时颜色
+
+ [Header("运行时选中/边框颜色")]
+ [Tooltip("运行时单选高亮")]
+ public Color RuntimeSelectionColor = new Color(0.18f, 0.42f, 0.82f, 0.25f);
+
+ [Tooltip("运行时多选高亮")]
+ public Color RuntimeMultiSelectColor = new Color(0.18f, 0.42f, 0.82f, 0.12f);
+
+ [Tooltip("运行时焦点高亮(当前选中格)")]
+ public Color RuntimeFocusColor = new Color(0.22f, 0.55f, 0.95f, 0.35f);
+
+ [Tooltip("运行时边框色")]
+ public Color RuntimeBorderColor = new Color(0.35f, 0.35f, 0.35f, 0.5f);
+
+ [Tooltip("运行时边框宽度")]
+ public float RuntimeBorderWidth = 1f;
+
+ #endregion
+
+ #region 编辑器多选颜色因子
+
+ [Header("编辑器多选/焦点颜色因子(基于 SelectionColor 计算)")]
+ [Tooltip("多选透明因子")]
+ [Range(0, 1)] public float MultiSelectAlphaFactor = 0.4f;
+
+ [Tooltip("焦点色 R 增量")]
+ [Range(0, 0.5f)] public float FocusRAdd = 0.04f;
+
+ [Tooltip("焦点色 G 增量")]
+ [Range(0, 0.5f)] public float FocusGAdd = 0.13f;
+
+ [Tooltip("焦点色 B 增量")]
+ [Range(0, 0.5f)] public float FocusBAdd = 0.13f;
+
+ [Tooltip("焦点色 Alpha 倍数")]
+ [Range(0.1f, 3f)] public float FocusAlphaMul = 1.4f;
+
+ #endregion
+
+ #region 资源路径
+
+ /// Resources 目录下的默认配置文件名(不含扩展名)
+ public const string DEFAULT_RESOURCE_PATH = "XTableDefaultConfig";
+
+ /// 从 Resources 加载默认配置,若失败则返回 ScriptableObject.CreateInstance 的默认值
+ public static XTableConfig LoadOrDefault()
+ {
+ var cfg = Resources.Load(DEFAULT_RESOURCE_PATH);
+ if (cfg != null) return cfg;
+ return CreateInstance();
+ }
+
+ #endregion
+ }
+}
diff --git a/Runtime/XTable/Core/XTableConfig.cs.meta b/Runtime/XTable/Core/XTableConfig.cs.meta
new file mode 100644
index 0000000..57f4c9b
--- /dev/null
+++ b/Runtime/XTable/Core/XTableConfig.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 94d64cced79c6ef41af29f7473ff5105
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/XTable/Core/XTableQuadtree.cs b/Runtime/XTable/Core/XTableQuadtree.cs
index 1ec3b63..997f757 100644
--- a/Runtime/XTable/Core/XTableQuadtree.cs
+++ b/Runtime/XTable/Core/XTableQuadtree.cs
@@ -65,12 +65,17 @@ namespace XericUI.XTable.Core
private Node m_Root;
private float[] m_RowHeights;
private float[] m_ColWidths;
+ private int m_MaxCellsPerNode;
/// 四叉树是否已构建完成
public bool IsBuilt { get; private set; }
#endregion
+ #region 常量
+
+ #endregion
+
#region 构建
///
@@ -83,7 +88,7 @@ namespace XericUI.XTable.Core
/// 所有有数据的单元格元数据列表
public void Build(float totalWidth, float totalHeight,
float[] rowHeights, float[] colWidths,
- List cells)
+ List cells, int maxCellsPerNode = 64)
{
if (rowHeights == null || colWidths == null || cells == null)
{
@@ -93,6 +98,7 @@ namespace XericUI.XTable.Core
m_RowHeights = rowHeights;
m_ColWidths = colWidths;
+ m_MaxCellsPerNode = maxCellsPerNode;
m_Root = new Node { Region = new Rect(0, 0, totalWidth, totalHeight) };
int maxRow = rowHeights.Length - 1;
@@ -109,10 +115,10 @@ namespace XericUI.XTable.Core
/// 强制重建(外部入口,通常由表格组件在数据/布局变更后调用)
public void ForceRebuild(float totalWidth, float totalHeight,
float[] rowHeights, float[] colWidths,
- List cells)
+ List cells, int maxCellsPerNode = 64)
{
Clear();
- Build(totalWidth, totalHeight, rowHeights, colWidths, cells);
+ Build(totalWidth, totalHeight, rowHeights, colWidths, cells, maxCellsPerNode);
}
private void BuildNode(Node node, List allCells,
@@ -149,11 +155,20 @@ namespace XericUI.XTable.Core
if (allSame)
{
- node.UniformNamespace = firstNs;
- node.Cells = new List<(int, int)>(cellsInRange.Count);
- for (int i = 0; i < cellsInRange.Count; i++)
- node.Cells.Add((cellsInRange[i].Row, cellsInRange[i].Col));
- return;
+ // 命名空间统一,但若空间跨度过大则继续分裂以便按块跳过不可见区域
+ if (cellsInRange.Count > m_MaxCellsPerNode &&
+ (minRow < maxRow || minCol < maxCol))
+ {
+ // 继续执行分裂逻辑(不要 return)
+ }
+ else
+ {
+ node.UniformNamespace = firstNs;
+ node.Cells = new List<(int, int)>(cellsInRange.Count);
+ for (int i = 0; i < cellsInRange.Count; i++)
+ node.Cells.Add((cellsInRange[i].Row, cellsInRange[i].Col));
+ return;
+ }
}
// 无法继续分裂(单行单列),强制标记为均匀
diff --git a/Runtime/XTable/Rendering/Component/TableRenderer.cs b/Runtime/XTable/Rendering/Component/TableRenderer.cs
index 6f7760d..691d2e6 100644
--- a/Runtime/XTable/Rendering/Component/TableRenderer.cs
+++ b/Runtime/XTable/Rendering/Component/TableRenderer.cs
@@ -29,6 +29,13 @@ namespace XericUI.XTable.Rendering.Component
/// Texture2D → Sprite 缓存,避免每帧分配
private Dictionary m_SpriteCache;
+ /// 单元格内容水平内边距(单侧),由 XericUIActionTable 设置
+ public float CellPadding;
+ private float CellPadding2 => CellPadding * 2f;
+
+ /// 表格全局配置资源,由 XericUIActionTable 设置
+ public XTableConfig Config;
+
#endregion
#region 公开属性
@@ -194,8 +201,8 @@ namespace XericUI.XTable.Rendering.Component
float borderWidth = GetStyleFloat(defaultNs, XericUIActionTable.STYLE_CELL_BORDER_BOTTOM_WIDTH,
XericUIActionTable.BORDER_WIDTH_FALLBACK);
- 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);
+ Color multiSelectColor = new Color(selectionColor.r, selectionColor.g, selectionColor.b, selectionColor.a * Config.MultiSelectAlphaFactor);
+ Color focusColor = new Color(selectionColor.r + Config.FocusRAdd, selectionColor.g + Config.FocusGAdd, selectionColor.b + Config.FocusBAdd, selectionColor.a * Config.FocusAlphaMul);
int selRow = GetSelectedRow();
int selCol = GetSelectedCol();
@@ -258,8 +265,8 @@ namespace XericUI.XTable.Rendering.Component
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.Rect.anchoredPosition = new Vector2(cellX + CellPadding, cellY);
+ txt.Rect.sizeDelta = new Vector2(cellW - CellPadding2, cellH);
txt.Text.text = data.Text;
txt.Text.color = GetStyleColor(cellNS, XericUIActionTable.STYLE_CELL_FG_COLOR,
XericUIActionTable.FG_COLOR_FALLBACK);
@@ -275,8 +282,8 @@ namespace XericUI.XTable.Rendering.Component
{
Sprite sprite = GetOrCreateSprite(data.Image);
var img = m_Assembler.GetImage("cell_image", cellNS);
- img.Rect.anchoredPosition = new Vector2(cellX + 4, cellY);
- img.Rect.sizeDelta = new Vector2(cellW - 8, cellH);
+ img.Rect.anchoredPosition = new Vector2(cellX + CellPadding, cellY);
+ img.Rect.sizeDelta = new Vector2(cellW - CellPadding2, cellH);
img.Image.sprite = sprite;
}
break;
@@ -300,9 +307,9 @@ namespace XericUI.XTable.Rendering.Component
private void RenderCellsRuntime(int sr, int er, int sc, int ec,
float[] rowHeights, float[] colWidths, XTableData tableData, string defaultNs)
{
- Color rtSelectionColor = XericUIActionTable.RT_SELECTION_COLOR;
- Color rtMultiSelectColor = XericUIActionTable.RT_MULTI_SELECT_COLOR;
- Color rtFocusColor = XericUIActionTable.RT_FOCUS_COLOR;
+ Color rtSelectionColor = Config.RuntimeSelectionColor;
+ Color rtMultiSelectColor = Config.RuntimeMultiSelectColor;
+ Color rtFocusColor = Config.RuntimeFocusColor;
int selRow = GetSelectedRow();
int selCol = GetSelectedCol();
@@ -347,13 +354,13 @@ namespace XericUI.XTable.Rendering.Component
var hLine = m_Assembler.GetImage("cell_hline");
hLine.Rect.anchoredPosition = new Vector2(cellX, cellY - cellH);
- hLine.Rect.sizeDelta = new Vector2(cellW, XericUIActionTable.RT_BORDER_WIDTH);
- hLine.Image.color = XericUIActionTable.RT_BORDER_COLOR;
+ hLine.Rect.sizeDelta = new Vector2(cellW, Config.RuntimeBorderWidth);
+ hLine.Image.color = Config.RuntimeBorderColor;
var vLine = m_Assembler.GetImage("cell_vline");
- vLine.Rect.anchoredPosition = new Vector2(cellX + cellW - XericUIActionTable.RT_BORDER_WIDTH, cellY);
- vLine.Rect.sizeDelta = new Vector2(XericUIActionTable.RT_BORDER_WIDTH, cellH);
- vLine.Image.color = XericUIActionTable.RT_BORDER_COLOR;
+ vLine.Rect.anchoredPosition = new Vector2(cellX + cellW - Config.RuntimeBorderWidth, cellY);
+ vLine.Rect.sizeDelta = new Vector2(Config.RuntimeBorderWidth, cellH);
+ vLine.Image.color = Config.RuntimeBorderColor;
if (data == null) continue;
@@ -363,8 +370,8 @@ namespace XericUI.XTable.Rendering.Component
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.Rect.anchoredPosition = new Vector2(cellX + CellPadding, cellY);
+ txt.Rect.sizeDelta = new Vector2(cellW - CellPadding2, cellH);
txt.Text.text = data.Text;
}
break;
@@ -373,8 +380,8 @@ namespace XericUI.XTable.Rendering.Component
{
Sprite sprite = GetOrCreateSprite(data.Image);
var img = m_Assembler.GetImage("cell_image", cellNS);
- img.Rect.anchoredPosition = new Vector2(cellX + 4, cellY);
- img.Rect.sizeDelta = new Vector2(cellW - 8, cellH);
+ img.Rect.anchoredPosition = new Vector2(cellX + CellPadding, cellY);
+ img.Rect.sizeDelta = new Vector2(cellW - CellPadding2, cellH);
img.Image.sprite = sprite;
}
break;
diff --git a/Runtime/XTable/Rendering/Component/XericUIActionTable.cs b/Runtime/XTable/Rendering/Component/XericUIActionTable.cs
index cfc3f97..c1f0894 100644
--- a/Runtime/XTable/Rendering/Component/XericUIActionTable.cs
+++ b/Runtime/XTable/Rendering/Component/XericUIActionTable.cs
@@ -10,7 +10,6 @@ using XericUI.XTable.Mapping;
using XericUI.XTable.Rendering.Elements;
using XericLibrary.Runtime.SuperStyleSheet;
using XericLibrary.Runtime.UIGraph;
-using XericUI.XTable.Core;
#if UNITY_EDITOR
using UnityEditor;
#endif
@@ -26,12 +25,6 @@ namespace XericUI.XTable.Rendering.Component
[AddComponentMenu("Xeric UI Vessel/Table/Xeric UI Action Table", 60)]
public partial class XericUIActionTable : XericUIBehaciour, IPointerClickHandler
{
- #region 常量
-
- private const string DEFAULT_STYLE_NS = "xeric_table_default";
-
- #endregion
-
#region 序列化字段
[SerializeField] private XTableData m_TableData;
@@ -40,7 +33,11 @@ namespace XericUI.XTable.Rendering.Component
[SerializeField] private float[] m_ColWidths = new float[] { 100f, 80f, 120f };
- [SerializeField] private string m_DefaultStyleNamespace = DEFAULT_STYLE_NS;
+ [SerializeField] private string m_DefaultStyleNamespace = "";
+
+ [SerializeField]
+ [Tooltip("表格全局配置资源")]
+ private XTableConfig m_Config;
[SerializeField] private ScrollRect m_ScrollRect;
@@ -186,6 +183,23 @@ namespace XericUI.XTable.Rendering.Component
}
}
+ /// 表格全局配置资源
+ public XTableConfig Config
+ {
+ get
+ {
+ if (m_Config == null)
+ m_Config = XTableConfig.LoadOrDefault();
+ return m_Config;
+ }
+ set => m_Config = value;
+ }
+
+ /// 单元格内容水平内边距(单侧)
+ private float CellPadding => Config.CellHorizontalPadding;
+ /// 单元格内容宽度扣除量
+ private float CellPadding2 => Config.CellHorizontalPadding * 2f;
+
///
/// 基于四叉树查询结果渲染可见象限内的单元格内容(文本/预制体/选择高亮)。
/// 边框由 统一绘制。
@@ -198,8 +212,8 @@ namespace XericUI.XTable.Rendering.Component
if (!Application.isPlaying)
{
Color selectionColor = GetCellSelectionBgColor(ns);
- 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);
+ Color multiSelectColor = new Color(selectionColor.r, selectionColor.g, selectionColor.b, selectionColor.a * Config.MultiSelectAlphaFactor);
+ Color focusColor = new Color(selectionColor.r + Config.FocusRAdd, selectionColor.g + Config.FocusGAdd, selectionColor.b + Config.FocusBAdd, selectionColor.a * Config.FocusAlphaMul);
foreach (var q in quadrants)
{
@@ -261,8 +275,8 @@ namespace XericUI.XTable.Rendering.Component
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.Rect.anchoredPosition = new Vector2(cellX + CellPadding, cellY);
+ txt.Rect.sizeDelta = new Vector2(cellW - CellPadding2, cellH);
txt.Text.text = data.Text;
txt.Text.color = GetCellFgColor(cellNS);
txt.Text.fontSize = GetCellFontSize(cellNS);
@@ -275,8 +289,8 @@ namespace XericUI.XTable.Rendering.Component
{
Sprite sprite = GetOrCreateSprite(data.Image);
var img = m_Assembler.GetImage("cell_image", cellNS);
- img.Rect.anchoredPosition = new Vector2(cellX + 4, cellY);
- img.Rect.sizeDelta = new Vector2(cellW - 8, cellH);
+ img.Rect.anchoredPosition = new Vector2(cellX + CellPadding, cellY);
+ img.Rect.sizeDelta = new Vector2(cellW - CellPadding2, cellH);
img.Image.sprite = sprite;
}
break;
@@ -300,9 +314,9 @@ namespace XericUI.XTable.Rendering.Component
#endif
// 运行时模式
- Color rtSelectionColor = RT_SELECTION_COLOR;
- Color rtMultiSelectColor = RT_MULTI_SELECT_COLOR;
- Color rtFocusColor = RT_FOCUS_COLOR;
+ Color rtSelectionColor = Config.RuntimeSelectionColor;
+ Color rtMultiSelectColor = Config.RuntimeMultiSelectColor;
+ Color rtFocusColor = Config.RuntimeFocusColor;
foreach (var q in quadrants)
{
@@ -362,8 +376,8 @@ namespace XericUI.XTable.Rendering.Component
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.Rect.anchoredPosition = new Vector2(cellX + CellPadding, cellY);
+ txt.Rect.sizeDelta = new Vector2(cellW - CellPadding2, cellH);
txt.Text.text = data.Text;
}
break;
@@ -372,8 +386,8 @@ namespace XericUI.XTable.Rendering.Component
{
Sprite sprite = GetOrCreateSprite(data.Image);
var img = m_Assembler.GetImage("cell_image", cellNS);
- img.Rect.anchoredPosition = new Vector2(cellX + 4, cellY);
- img.Rect.sizeDelta = new Vector2(cellW - 8, cellH);
+ img.Rect.anchoredPosition = new Vector2(cellX + CellPadding, cellY);
+ img.Rect.sizeDelta = new Vector2(cellW - CellPadding2, cellH);
img.Image.sprite = sprite;
}
break;
@@ -405,6 +419,12 @@ namespace XericUI.XTable.Rendering.Component
// 域重载后旧子对象可能残留在场景中(DontSave 不自动销毁),先清空再重建
ClearAllChildren();
+ if (m_Config == null)
+ m_Config = XTableConfig.LoadOrDefault();
+
+ if (string.IsNullOrEmpty(m_DefaultStyleNamespace))
+ m_DefaultStyleNamespace = Config.DefaultStyleNamespace;
+
if (m_TableData == null)
m_TableData = new XTableData();
@@ -675,9 +695,10 @@ namespace XericUI.XTable.Rendering.Component
public bool IsMergeSource(int row, int col, out int rowSpan, out int colSpan)
=> TableData.IsMergeSource(row, col, out rowSpan, out colSpan);
- /// 在末尾追加一行,默认行高 40
- public void AddRow(float height = 40f)
+ /// 在末尾追加一行,默认行高来自 Config
+ public void AddRow(float height = -1f)
{
+ if (height <= 0) height = Config.DefaultRowHeight;
#if UNITY_EDITOR
UnityEditor.Undo.RecordObject(this, "Add Table Row");
#endif
@@ -692,9 +713,10 @@ namespace XericUI.XTable.Rendering.Component
#endif
}
- /// 在末尾追加一列,默认列宽 100
- public void AddColumn(float width = 100f)
+ /// 在末尾追加一列,默认列宽来自 Config
+ public void AddColumn(float width = -1f)
{
+ if (width <= 0) width = Config.DefaultColumnWidth;
#if UNITY_EDITOR
UnityEditor.Undo.RecordObject(this, "Add Table Column");
#endif
@@ -1243,8 +1265,8 @@ namespace XericUI.XTable.Rendering.Component
Color borderColor = GetCellBorderColor(ns);
float borderWidth = GetCellBorderWidth(ns);
- 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);
+ Color multiSelectColor = new Color(selectionColor.r, selectionColor.g, selectionColor.b, selectionColor.a * Config.MultiSelectAlphaFactor);
+ Color focusColor = new Color(selectionColor.r + Config.FocusRAdd, selectionColor.g + Config.FocusGAdd, selectionColor.b + Config.FocusBAdd, selectionColor.a * Config.FocusAlphaMul);
for (int r = sr; r < er && r < m_RowHeights.Length; r++)
{
@@ -1308,8 +1330,8 @@ namespace XericUI.XTable.Rendering.Component
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.Rect.anchoredPosition = new Vector2(cellX + CellPadding, cellY);
+ txt.Rect.sizeDelta = new Vector2(cellW - CellPadding2, cellH);
txt.Text.text = data.Text;
txt.Text.color = GetCellFgColor(cellNS);
txt.Text.fontSize = GetCellFontSize(cellNS);
@@ -1322,8 +1344,8 @@ namespace XericUI.XTable.Rendering.Component
{
Sprite sprite = GetOrCreateSprite(data.Image);
var img = m_Assembler.GetImage("cell_image", cellNS);
- img.Rect.anchoredPosition = new Vector2(cellX + 4, cellY);
- img.Rect.sizeDelta = new Vector2(cellW - 8, cellH);
+ img.Rect.anchoredPosition = new Vector2(cellX + CellPadding, cellY);
+ img.Rect.sizeDelta = new Vector2(cellW - CellPadding2, cellH);
img.Image.sprite = sprite;
}
break;
@@ -1346,9 +1368,9 @@ namespace XericUI.XTable.Rendering.Component
#endif
// 运行时模式
- Color rtSelectionColor = RT_SELECTION_COLOR;
- Color rtMultiSelectColor = RT_MULTI_SELECT_COLOR;
- Color rtFocusColor = RT_FOCUS_COLOR;
+ Color rtSelectionColor = Config.RuntimeSelectionColor;
+ Color rtMultiSelectColor = Config.RuntimeMultiSelectColor;
+ Color rtFocusColor = Config.RuntimeFocusColor;
for (int r = sr; r < er && r < m_RowHeights.Length; r++)
{
@@ -1393,13 +1415,13 @@ namespace XericUI.XTable.Rendering.Component
var hLine = m_Assembler.GetImage("cell_hline");
hLine.Rect.anchoredPosition = new Vector2(cellX, cellY - cellH);
- hLine.Rect.sizeDelta = new Vector2(cellW, RT_BORDER_WIDTH);
- hLine.Image.color = RT_BORDER_COLOR;
+ hLine.Rect.sizeDelta = new Vector2(cellW, Config.RuntimeBorderWidth);
+ hLine.Image.color = Config.RuntimeBorderColor;
var vLine = m_Assembler.GetImage("cell_vline");
- vLine.Rect.anchoredPosition = new Vector2(cellX + cellW - RT_BORDER_WIDTH, cellY);
- vLine.Rect.sizeDelta = new Vector2(RT_BORDER_WIDTH, cellH);
- vLine.Image.color = RT_BORDER_COLOR;
+ vLine.Rect.anchoredPosition = new Vector2(cellX + cellW - Config.RuntimeBorderWidth, cellY);
+ vLine.Rect.sizeDelta = new Vector2(Config.RuntimeBorderWidth, cellH);
+ vLine.Image.color = Config.RuntimeBorderColor;
if (data == null) continue;
@@ -1409,8 +1431,8 @@ namespace XericUI.XTable.Rendering.Component
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.Rect.anchoredPosition = new Vector2(cellX + CellPadding, cellY);
+ txt.Rect.sizeDelta = new Vector2(cellW - CellPadding2, cellH);
txt.Text.text = data.Text;
// 运行时样式由 StyleBoundElement 被动更新,此处仅设置文本内容
}
@@ -1420,8 +1442,8 @@ namespace XericUI.XTable.Rendering.Component
{
Sprite sprite = GetOrCreateSprite(data.Image);
var img = m_Assembler.GetImage("cell_image", cellNS);
- img.Rect.anchoredPosition = new Vector2(cellX + 4, cellY);
- img.Rect.sizeDelta = new Vector2(cellW - 8, cellH);
+ img.Rect.anchoredPosition = new Vector2(cellX + CellPadding, cellY);
+ img.Rect.sizeDelta = new Vector2(cellW - CellPadding2, cellH);
img.Image.sprite = sprite;
}
break;
@@ -1676,7 +1698,7 @@ namespace XericUI.XTable.Rendering.Component
}
}
- m_Quadtree.Build(m_TotalWidth, m_TotalHeight, m_RowHeights, m_ColWidths, cells);
+ m_Quadtree.Build(m_TotalWidth, m_TotalHeight, m_RowHeights, m_ColWidths, cells, Config.QuadtreeMaxCellsPerNode);
}
#endregion
@@ -1756,12 +1778,12 @@ namespace XericUI.XTable.Rendering.Component
}
else
{
- borderColor = RT_BORDER_COLOR;
- borderWidth = RT_BORDER_WIDTH;
+ borderColor = Config.RuntimeBorderColor;
+ borderWidth = Config.RuntimeBorderWidth;
}
#else
- Color borderColor = RT_BORDER_COLOR;
- float borderWidth = RT_BORDER_WIDTH;
+ Color borderColor = Config.RuntimeBorderColor;
+ float borderWidth = Config.RuntimeBorderWidth;
#endif
int rows = m_RowHeights.Length;
@@ -1850,6 +1872,8 @@ namespace XericUI.XTable.Rendering.Component
// 共享预制体对象池
m_ViewportRenderer.PrefabPool = m_PrefabPool;
m_ViewportRenderer.ActivePrefabMap = m_ActivePrefabMap;
+ m_ViewportRenderer.CellPadding = Config.CellHorizontalPadding;
+ m_ViewportRenderer.Config = Config;
}
/// 渲染 Viewport 层冻结单元格,随滚动偏移调整位置
From 4e92cd6c7fbfe617007240050514db431d72349a Mon Sep 17 00:00:00 2001
From: LiRuoChen <571244399@qq.com>
Date: Fri, 10 Jul 2026 11:21:10 +0800
Subject: [PATCH 4/4] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E8=8F=9C=E5=8D=95?=
=?UTF-8?q?=E5=90=8D=E7=A7=B0=EF=BC=8C=E6=B7=BB=E5=8A=A0=E8=B5=84=E6=BA=90?=
=?UTF-8?q?=E9=A2=84=E8=BD=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Runtime/XTable/Core/XTableConfig.cs | 2 +-
.../Rendering/Component/XericUIActionTable.cs | 22 +++++++++++++++++++
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/Runtime/XTable/Core/XTableConfig.cs b/Runtime/XTable/Core/XTableConfig.cs
index ff7efcb..e8a2db1 100644
--- a/Runtime/XTable/Core/XTableConfig.cs
+++ b/Runtime/XTable/Core/XTableConfig.cs
@@ -7,7 +7,7 @@ namespace XericUI.XTable.Core
/// 表格组件在 Awake 时自动加载 Resources 中的 "XTableDefaultConfig",
/// 或由外部脚本在初始化阶段显式赋值。
///
- [CreateAssetMenu(fileName = "XTableConfig", menuName = "Xeric UI/Table/Table Config", order = 100)]
+ [CreateAssetMenu(fileName = "XTableConfig", menuName = "Xeric Library/Table/Table Config", order = 100)]
public class XTableConfig : ScriptableObject
{
#region 布局
diff --git a/Runtime/XTable/Rendering/Component/XericUIActionTable.cs b/Runtime/XTable/Rendering/Component/XericUIActionTable.cs
index c1f0894..000ca60 100644
--- a/Runtime/XTable/Rendering/Component/XericUIActionTable.cs
+++ b/Runtime/XTable/Rendering/Component/XericUIActionTable.cs
@@ -412,10 +412,32 @@ namespace XericUI.XTable.Rendering.Component
#region 生命周期
+ private static bool s_StyleSheetsPreloaded;
+
+ ///
+ /// 预加载 Resources 目录下所有 XericStyleSheet 资产到 StyleManager。
+ /// 仅首次调用生效,后续调用直接跳过。
+ ///
+ private static void PreloadAllStyleSheets()
+ {
+ if (s_StyleSheetsPreloaded) return;
+ s_StyleSheetsPreloaded = true;
+
+ var sheets = Resources.LoadAll("");
+ foreach (var sheet in sheets)
+ {
+ if (sheet != null)
+ StyleManager.LoadStyleSheet(sheet);
+ }
+ }
+
protected override void Awake()
{
base.Awake();
+ // 预加载 Resources 中所有 .xsss 样式表到 StyleManager(仅首次)
+ PreloadAllStyleSheets();
+
// 域重载后旧子对象可能残留在场景中(DontSave 不自动销毁),先清空再重建
ClearAllChildren();