优化表格边框绘制逻辑,添加边框缓存。
This commit is contained in:
@@ -914,17 +914,24 @@ namespace XericUIEditor.XTable
|
||||
table.SelectedRow, table.SelectedCol) ?? "";
|
||||
|
||||
var namespaces = StyleManager.GetAvailableNamespaces();
|
||||
int currentIdx = namespaces.IndexOf(currentNS);
|
||||
// 构建显示列表:如果当前命名空间不在可用列表中则追加到末尾
|
||||
var displayNamespaces = new System.Collections.Generic.List<string>(namespaces);
|
||||
int currentIdx = displayNamespaces.IndexOf(currentNS);
|
||||
if (currentIdx < 0 && !string.IsNullOrEmpty(currentNS))
|
||||
{
|
||||
displayNamespaces.Add(currentNS);
|
||||
currentIdx = displayNamespaces.Count - 1;
|
||||
}
|
||||
if (currentIdx < 0) currentIdx = 0;
|
||||
|
||||
Rect dropRect = new Rect(barRect.x + 44, row2Y, barW - 44 - pad, rowH);
|
||||
int newIdx = UnityEditor.EditorGUI.Popup(dropRect, currentIdx,
|
||||
namespaces.ToArray(), UnityEditor.EditorStyles.popup);
|
||||
displayNamespaces.ToArray(), UnityEditor.EditorStyles.popup);
|
||||
|
||||
if (newIdx != currentIdx && newIdx >= 0 && newIdx < namespaces.Count)
|
||||
if (newIdx != currentIdx && newIdx >= 0 && newIdx < displayNamespaces.Count)
|
||||
{
|
||||
table.SetCellStyleNamespace(table.SelectedRow, table.SelectedCol,
|
||||
namespaces[newIdx]);
|
||||
displayNamespaces[newIdx]);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -33,6 +33,11 @@ namespace XericUI.XTable.Core
|
||||
/// <summary>合并单元格描述列表</summary>
|
||||
public List<XTableMergeDescriptor> MergeDescriptors;
|
||||
|
||||
/// <summary>每个单元格右侧边框的样式命名空间缓存(线性数组,同 Cells[] 布局)</summary>
|
||||
public string[] BorderRightNs;
|
||||
/// <summary>每个单元格底部边框的样式命名空间缓存(线性数组,同 Cells[] 布局)</summary>
|
||||
public string[] BorderBottomNs;
|
||||
|
||||
/// <summary>
|
||||
/// 创建指定尺寸的块
|
||||
/// </summary>
|
||||
@@ -42,6 +47,8 @@ namespace XericUI.XTable.Core
|
||||
BlockSizeY = blockSizeY;
|
||||
Cells = new XTableCellData[blockSizeX * blockSizeY];
|
||||
MergeDescriptors = new List<XTableMergeDescriptor>();
|
||||
BorderRightNs = new string[blockSizeX * blockSizeY];
|
||||
BorderBottomNs = new string[blockSizeX * blockSizeY];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -74,6 +81,38 @@ namespace XericUI.XTable.Core
|
||||
Cells[index] = data;
|
||||
}
|
||||
|
||||
/// <summary>通过块内局部坐标获取右侧边框缓存</summary>
|
||||
public string GetBorderRight(int localRow, int localCol)
|
||||
{
|
||||
int index = localRow * BlockSizeX + localCol;
|
||||
if (index < 0 || index >= (BorderRightNs?.Length ?? 0)) return null;
|
||||
return BorderRightNs[index];
|
||||
}
|
||||
|
||||
/// <summary>通过块内局部坐标设置右侧边框缓存</summary>
|
||||
public void SetBorderRight(int localRow, int localCol, string ns)
|
||||
{
|
||||
int index = localRow * BlockSizeX + localCol;
|
||||
if (index < 0 || index >= (BorderRightNs?.Length ?? 0)) return;
|
||||
BorderRightNs[index] = ns;
|
||||
}
|
||||
|
||||
/// <summary>通过块内局部坐标获取底部边框缓存</summary>
|
||||
public string GetBorderBottom(int localRow, int localCol)
|
||||
{
|
||||
int index = localRow * BlockSizeX + localCol;
|
||||
if (index < 0 || index >= (BorderBottomNs?.Length ?? 0)) return null;
|
||||
return BorderBottomNs[index];
|
||||
}
|
||||
|
||||
/// <summary>通过块内局部坐标设置底部边框缓存</summary>
|
||||
public void SetBorderBottom(int localRow, int localCol, string ns)
|
||||
{
|
||||
int index = localRow * BlockSizeX + localCol;
|
||||
if (index < 0 || index >= (BorderBottomNs?.Length ?? 0)) return;
|
||||
BorderBottomNs[index] = ns;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否有合并描述重定向此单元格
|
||||
/// </summary>
|
||||
@@ -103,6 +142,10 @@ namespace XericUI.XTable.Core
|
||||
// 确保数组和列表非空
|
||||
if (Cells == null) Cells = new XTableCellData[BlockSizeX * BlockSizeY];
|
||||
if (MergeDescriptors == null) MergeDescriptors = new List<XTableMergeDescriptor>();
|
||||
if (BorderRightNs == null || BorderRightNs.Length != BlockSizeX * BlockSizeY)
|
||||
BorderRightNs = new string[BlockSizeX * BlockSizeY];
|
||||
if (BorderBottomNs == null || BorderBottomNs.Length != BlockSizeX * BlockSizeY)
|
||||
BorderBottomNs = new string[BlockSizeX * BlockSizeY];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -407,5 +407,170 @@ namespace XericUI.XTable.Core
|
||||
public int BlockCount => BlockMap.Count;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 边框缓存
|
||||
|
||||
/// <summary>
|
||||
/// 外边框样式管理器——维护 -1 行 / -1 列的边框样式命名空间。
|
||||
/// key = (row, col),其中 row / col 可为 -1。
|
||||
/// (-1, -1) = 表格最外框,
|
||||
/// (-1, c) = 第 c 列顶部边框,
|
||||
/// (r, -1) = 第 r 行左侧边框。
|
||||
/// </summary>
|
||||
[NonSerialized] public Dictionary<(int row, int col), string> OuterBorderNs;
|
||||
|
||||
// OuterBorderNs 序列化代理
|
||||
[SerializeField] private List<int> m_OuterBorderRows = new List<int>();
|
||||
[SerializeField] private List<int> m_OuterBorderCols = new List<int>();
|
||||
[SerializeField] private List<string> m_OuterBorderValues = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// 获取右侧边框样式命名空间。
|
||||
/// col < 0 时退回到 OuterBorderNs。
|
||||
/// </summary>
|
||||
public string GetBorderRightNs(int row, int col)
|
||||
{
|
||||
if (col < 0 || row < 0)
|
||||
return GetOuterBorderNs(row, col);
|
||||
|
||||
XTableCoordinateUtility.CellToBlockCoordinate(row, col, BlockSizeX, BlockSizeY,
|
||||
out int blockRow, out int blockCol,
|
||||
out int localRow, out int localCol);
|
||||
ulong zIndex = XTableBlockMapping.BlockCoordToZIndex(blockRow, blockCol);
|
||||
|
||||
if (!BlockMap.TryGetValue(zIndex, out XTableBlock block))
|
||||
return null;
|
||||
return block.GetBorderRight(localRow, localCol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置右侧边框样式命名空间。
|
||||
/// col < 0 时写入 OuterBorderNs。
|
||||
/// </summary>
|
||||
public void SetBorderRightNs(int row, int col, string ns)
|
||||
{
|
||||
if (col < 0 || row < 0)
|
||||
{
|
||||
SetOuterBorderNs(row, col, ns);
|
||||
return;
|
||||
}
|
||||
|
||||
XTableCoordinateUtility.CellToBlockCoordinate(row, col, BlockSizeX, BlockSizeY,
|
||||
out int blockRow, out int blockCol,
|
||||
out int localRow, out int localCol);
|
||||
ulong zIndex = XTableBlockMapping.BlockCoordToZIndex(blockRow, blockCol);
|
||||
|
||||
if (!BlockMap.TryGetValue(zIndex, out XTableBlock block))
|
||||
{
|
||||
block = new XTableBlock(BlockSizeX, BlockSizeY, blockRow, blockCol);
|
||||
BlockMap[zIndex] = block;
|
||||
}
|
||||
block.SetBorderRight(localRow, localCol, ns);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取底部边框样式命名空间。
|
||||
/// row < 0 时退回到 OuterBorderNs。
|
||||
/// </summary>
|
||||
public string GetBorderBottomNs(int row, int col)
|
||||
{
|
||||
if (col < 0 || row < 0)
|
||||
return GetOuterBorderNs(row, col);
|
||||
|
||||
XTableCoordinateUtility.CellToBlockCoordinate(row, col, BlockSizeX, BlockSizeY,
|
||||
out int blockRow, out int blockCol,
|
||||
out int localRow, out int localCol);
|
||||
ulong zIndex = XTableBlockMapping.BlockCoordToZIndex(blockRow, blockCol);
|
||||
|
||||
if (!BlockMap.TryGetValue(zIndex, out XTableBlock block))
|
||||
return null;
|
||||
return block.GetBorderBottom(localRow, localCol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置底部边框样式命名空间。
|
||||
/// row < 0 时写入 OuterBorderNs。
|
||||
/// </summary>
|
||||
public void SetBorderBottomNs(int row, int col, string ns)
|
||||
{
|
||||
if (col < 0 || row < 0)
|
||||
{
|
||||
SetOuterBorderNs(row, col, ns);
|
||||
return;
|
||||
}
|
||||
|
||||
XTableCoordinateUtility.CellToBlockCoordinate(row, col, BlockSizeX, BlockSizeY,
|
||||
out int blockRow, out int blockCol,
|
||||
out int localRow, out int localCol);
|
||||
ulong zIndex = XTableBlockMapping.BlockCoordToZIndex(blockRow, blockCol);
|
||||
|
||||
if (!BlockMap.TryGetValue(zIndex, out XTableBlock block))
|
||||
{
|
||||
block = new XTableBlock(BlockSizeX, BlockSizeY, blockRow, blockCol);
|
||||
BlockMap[zIndex] = block;
|
||||
}
|
||||
block.SetBorderBottom(localRow, localCol, ns);
|
||||
}
|
||||
|
||||
/// <summary>获取外边框样式(-1 行 / -1 列)</summary>
|
||||
public string GetOuterBorderNs(int row, int col)
|
||||
{
|
||||
if (OuterBorderNs == null) return null;
|
||||
OuterBorderNs.TryGetValue((row, col), out string ns);
|
||||
return ns;
|
||||
}
|
||||
|
||||
/// <summary>设置外边框样式(-1 行 / -1 列)</summary>
|
||||
public void SetOuterBorderNs(int row, int col, string ns)
|
||||
{
|
||||
if (OuterBorderNs == null)
|
||||
OuterBorderNs = new Dictionary<(int, int), string>();
|
||||
OuterBorderNs[(row, col)] = ns;
|
||||
}
|
||||
|
||||
/// <summary>清空所有边框缓存</summary>
|
||||
public void ClearAllBorderCache()
|
||||
{
|
||||
OuterBorderNs?.Clear();
|
||||
foreach (var kv in BlockMap)
|
||||
{
|
||||
var b = kv.Value;
|
||||
if (b.BorderRightNs != null)
|
||||
System.Array.Clear(b.BorderRightNs, 0, b.BorderRightNs.Length);
|
||||
if (b.BorderBottomNs != null)
|
||||
System.Array.Clear(b.BorderBottomNs, 0, b.BorderBottomNs.Length);
|
||||
}
|
||||
}
|
||||
|
||||
// ── OuterBorderNs 序列化 ──
|
||||
private void SerializeOuterBorder()
|
||||
{
|
||||
m_OuterBorderRows.Clear();
|
||||
m_OuterBorderCols.Clear();
|
||||
m_OuterBorderValues.Clear();
|
||||
if (OuterBorderNs != null)
|
||||
{
|
||||
foreach (var kv in OuterBorderNs)
|
||||
{
|
||||
m_OuterBorderRows.Add(kv.Key.row);
|
||||
m_OuterBorderCols.Add(kv.Key.col);
|
||||
m_OuterBorderValues.Add(kv.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DeserializeOuterBorder()
|
||||
{
|
||||
OuterBorderNs = new Dictionary<(int, int), string>();
|
||||
int count = System.Math.Min(m_OuterBorderRows.Count,
|
||||
System.Math.Min(m_OuterBorderCols.Count, m_OuterBorderValues.Count));
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (m_OuterBorderValues[i] != null)
|
||||
OuterBorderNs[(m_OuterBorderRows[i], m_OuterBorderCols[i])] = m_OuterBorderValues[i];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,14 +474,38 @@ namespace XericUI.XTable.Rendering.Component
|
||||
public XTableCellData GetCellData(int row, int col)
|
||||
=> TableData.GetOrCreateCell(row, col);
|
||||
|
||||
/// <summary>设置单元格的样式命名空间</summary>
|
||||
/// <summary>设置单元格的样式命名空间,同时写入边框缓存(谁最后设置归谁)</summary>
|
||||
public void SetCellStyleNamespace(int row, int col, string styleNamespace)
|
||||
{
|
||||
var data = TableData.GetOrCreateCell(row, col);
|
||||
data.StyleNamespace = styleNamespace;
|
||||
// 合并源:遍历所有被合并单元格,全部写入该样式
|
||||
if (TableData.IsMergeSource(row, col, out int rowSpan, out int colSpan))
|
||||
{
|
||||
for (int r = row; r < row + rowSpan; r++)
|
||||
{
|
||||
for (int c = col; c < col + colSpan; c++)
|
||||
{
|
||||
if (r < m_RowHeights.Length && c < m_ColWidths.Length)
|
||||
ApplyCellStyleToCell(r, c, styleNamespace);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyCellStyleToCell(row, col, styleNamespace);
|
||||
}
|
||||
|
||||
MarkDirty(TableDirtyType.StyleChanged);
|
||||
}
|
||||
|
||||
/// <summary>在单个单元格上设置样式,同时写入其右侧和底部的边框缓存</summary>
|
||||
private void ApplyCellStyleToCell(int row, int col, string ns)
|
||||
{
|
||||
var data = TableData.GetOrCreateCell(row, col);
|
||||
data.StyleNamespace = ns;
|
||||
TableData.SetBorderRightNs(row, col, ns);
|
||||
TableData.SetBorderBottomNs(row, col, ns);
|
||||
}
|
||||
|
||||
/// <summary>获取单元格的样式命名空间</summary>
|
||||
public string GetCellStyleNamespace(int row, int col)
|
||||
{
|
||||
@@ -1514,8 +1538,9 @@ namespace XericUI.XTable.Rendering.Component
|
||||
|
||||
/// <summary>
|
||||
/// 重建表格的全部边框线段。
|
||||
/// 遍历所有非合并覆盖的单元格,为每个单元格的右边界和下边界生成线段,
|
||||
/// 合并源单元格的线段位置取合并范围的最外沿,内部边界自动跳过。
|
||||
/// 第一阶段:从 OuterBorderNs 绘制 -1 行(顶部外框)和 -1 列(左侧外框)。
|
||||
/// 第二阶段:遍历非合并覆盖单元格,从边框缓存读取样式命名空间,按 per-cell 样式绘制右侧和底部边框。
|
||||
/// 合并源在最外沿绘制,内部边框自动跳过。
|
||||
/// </summary>
|
||||
private void RebuildBorders()
|
||||
{
|
||||
@@ -1525,31 +1550,50 @@ namespace XericUI.XTable.Rendering.Component
|
||||
var renderer = GetOrCreateBorderRenderer();
|
||||
renderer.ClearAll();
|
||||
|
||||
// 更新边框渲染器的尺寸,使其覆盖整个表格区域
|
||||
var borderRt = renderer.GetComponent<RectTransform>();
|
||||
borderRt.sizeDelta = new Vector2(m_TotalWidth, m_TotalHeight);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
Color borderColor;
|
||||
float borderWidth;
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
borderColor = GetCellBorderColor(m_DefaultStyleNamespace);
|
||||
borderWidth = GetCellBorderWidth(m_DefaultStyleNamespace);
|
||||
}
|
||||
else
|
||||
{
|
||||
borderColor = RT_BORDER_COLOR;
|
||||
borderWidth = RT_BORDER_WIDTH;
|
||||
}
|
||||
#else
|
||||
Color borderColor = RT_BORDER_COLOR;
|
||||
float borderWidth = RT_BORDER_WIDTH;
|
||||
#endif
|
||||
|
||||
int rows = m_RowHeights.Length;
|
||||
int cols = m_ColWidths.Length;
|
||||
|
||||
// ════════════════════════════════════════════
|
||||
// 阶段 1:-1 行(顶部外框)和 -1 列(左侧外框)
|
||||
// ════════════════════════════════════════════
|
||||
|
||||
// 顶部外框:从 col=0 到 col=cols-1,每列一段
|
||||
float topY = 0;
|
||||
for (int c = 0; c < cols; c++)
|
||||
{
|
||||
string ns = m_TableData?.GetOuterBorderNs(-1, c);
|
||||
if (string.IsNullOrEmpty(ns)) ns = m_DefaultStyleNamespace;
|
||||
Color color = GetCellBorderColor(ns);
|
||||
float width = GetCellBorderWidth(ns);
|
||||
float leftX = GetColLeftX(c);
|
||||
renderer.DrawLine(
|
||||
new Vector2(leftX, topY),
|
||||
new Vector2(leftX + m_ColWidths[c], topY),
|
||||
color, width, UVMode.ByDistance);
|
||||
}
|
||||
|
||||
// 左侧外框:从 row=0 到 row=rows-1,每行一段
|
||||
float xEdge = 0;
|
||||
for (int r = 0; r < rows; r++)
|
||||
{
|
||||
string ns = m_TableData?.GetOuterBorderNs(r, -1);
|
||||
if (string.IsNullOrEmpty(ns)) ns = m_DefaultStyleNamespace;
|
||||
Color color = GetCellBorderColor(ns);
|
||||
float width = GetCellBorderWidth(ns);
|
||||
float rowTopY = -GetRowTopY(r);
|
||||
renderer.DrawLine(
|
||||
new Vector2(xEdge, rowTopY),
|
||||
new Vector2(xEdge, rowTopY - m_RowHeights[r]),
|
||||
color, width, UVMode.ByDistance);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════
|
||||
// 阶段 2:每个单元格的右侧和底部边框
|
||||
// ════════════════════════════════════════════
|
||||
|
||||
for (int r = 0; r < rows; r++)
|
||||
{
|
||||
for (int c = 0; c < cols; c++)
|
||||
@@ -1576,21 +1620,35 @@ namespace XericUI.XTable.Rendering.Component
|
||||
float rightX = cellX + cellW;
|
||||
float bottomY = cellY - cellH;
|
||||
|
||||
// 右侧边框:右边有单元格时绘制
|
||||
// —— 右侧边框 ——
|
||||
string rightNs = m_TableData?.GetBorderRightNs(r, c);
|
||||
if (string.IsNullOrEmpty(rightNs)) rightNs = m_DefaultStyleNamespace;
|
||||
Color rightColor = GetCellBorderColor(rightNs);
|
||||
float rightWidth = GetCellBorderWidth(rightNs);
|
||||
|
||||
int rightCol = c + mergeCS;
|
||||
if (rightCol < cols)
|
||||
{
|
||||
renderer.DrawLine(
|
||||
new Vector2(rightX, cellY),
|
||||
new Vector2(rightX, bottomY),
|
||||
borderColor, borderWidth, UVMode.ByDistance);
|
||||
rightColor, rightWidth, UVMode.ByDistance);
|
||||
}
|
||||
|
||||
// —— 底部边框 ——
|
||||
string bottomNs = m_TableData?.GetBorderBottomNs(r, c);
|
||||
if (string.IsNullOrEmpty(bottomNs)) bottomNs = m_DefaultStyleNamespace;
|
||||
Color bottomColor = GetCellBorderColor(bottomNs);
|
||||
float bottomWidth = GetCellBorderWidth(bottomNs);
|
||||
|
||||
// 底部边框:下边有单元格时绘制
|
||||
int bottomRow = r + mergeRS;
|
||||
if (bottomRow < rows)
|
||||
{
|
||||
renderer.DrawLine(
|
||||
new Vector2(cellX, bottomY),
|
||||
new Vector2(rightX, bottomY),
|
||||
borderColor, borderWidth, UVMode.ByDistance);
|
||||
bottomColor, bottomWidth, UVMode.ByDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user