添加合并单元格的用法。
This commit is contained in:
@@ -229,12 +229,19 @@ namespace XericUI.XTable.Core
|
||||
BlockMap[zIndex] = block;
|
||||
}
|
||||
|
||||
// 查找或创建此块的合并描述(相同源)
|
||||
// 计算本块内合并区域的局部起始和跨度
|
||||
int localStartRow = Math.Max(0, startRow - blockRow * BlockSizeY);
|
||||
int localStartCol = Math.Max(0, startCol - blockCol * BlockSizeX);
|
||||
int blockEndRow = Math.Min((blockRow + 1) * BlockSizeY, startRow + rowSpan) - blockRow * BlockSizeY;
|
||||
int blockEndCol = Math.Min((blockCol + 1) * BlockSizeX, startCol + colSpan) - blockCol * BlockSizeX;
|
||||
|
||||
// 查找或创建此块的合并描述
|
||||
XTableMergeDescriptor descriptor = FindOrCreateMergeDescriptor(block,
|
||||
zIndex == srcZIndex ? srcLocalRow : -1,
|
||||
zIndex == srcZIndex ? srcLocalCol : -1,
|
||||
srcZIndex, srcLocalRow, srcLocalCol,
|
||||
zIndex != srcZIndex);
|
||||
zIndex != srcZIndex,
|
||||
localStartRow, localStartCol,
|
||||
blockEndRow - localStartRow, blockEndCol - localStartCol,
|
||||
rowSpan, colSpan);
|
||||
|
||||
descriptor.MergedCellSet.Add((localRow, localCol));
|
||||
}
|
||||
@@ -245,35 +252,41 @@ namespace XericUI.XTable.Core
|
||||
/// 查找或创建合并描述
|
||||
/// </summary>
|
||||
private XTableMergeDescriptor FindOrCreateMergeDescriptor(
|
||||
XTableBlock block, int checkLocalRow, int checkLocalCol,
|
||||
ulong srcZIndex, int srcLocalRow, int srcLocalCol, bool isCrossBlock)
|
||||
XTableBlock block,
|
||||
ulong srcZIndex, int srcLocalRow, int srcLocalCol, bool isCrossBlock,
|
||||
int localStartRow, int localStartCol, int blockRowSpan, int blockColSpan,
|
||||
int totalRowSpan, int totalColSpan)
|
||||
{
|
||||
// 查找已有描述
|
||||
// 查找已有描述:匹配源坐标和跨块标记
|
||||
for (int i = 0; i < block.MergeDescriptors.Count; i++)
|
||||
{
|
||||
var desc = block.MergeDescriptors[i];
|
||||
if (desc.MergeRowSpan > 0 && desc.MergeColSpan > 0)
|
||||
{
|
||||
// 简化的同源判断:跨块引用共享 sourceBlockIndex
|
||||
if (isCrossBlock && desc.IsCrossBlock && desc.SourceBlockIndex == srcZIndex)
|
||||
return desc;
|
||||
}
|
||||
if (desc.IsCrossBlock == isCrossBlock &&
|
||||
desc.SourceBlockIndex == srcZIndex &&
|
||||
desc.SourceLocalRow == srcLocalRow &&
|
||||
desc.SourceLocalCol == srcLocalCol)
|
||||
return desc;
|
||||
}
|
||||
|
||||
// 创建新描述
|
||||
// 创建新描述,设置完整跨度信息
|
||||
var newDesc = new XTableMergeDescriptor
|
||||
{
|
||||
IsCrossBlock = isCrossBlock,
|
||||
SourceBlockIndex = srcZIndex,
|
||||
SourceLocalRow = srcLocalRow,
|
||||
SourceLocalCol = srcLocalCol
|
||||
SourceLocalCol = srcLocalCol,
|
||||
LocalStartRow = localStartRow,
|
||||
LocalStartCol = localStartCol,
|
||||
MergeRowSpan = totalRowSpan,
|
||||
MergeColSpan = totalColSpan
|
||||
};
|
||||
block.MergeDescriptors.Add(newDesc);
|
||||
return newDesc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消指定区域的合并
|
||||
/// 取消指定坐标所在合并——同时处理"点击源坐标"和"点击被合并坐标"两种情况。
|
||||
/// 遍历所有块,移除所有指向该源的合并描述。
|
||||
/// </summary>
|
||||
public void UnmergeCells(int startRow, int startCol)
|
||||
{
|
||||
@@ -284,15 +297,43 @@ namespace XericUI.XTable.Core
|
||||
|
||||
ulong zIndex = XTableBlockMapping.BlockCoordToZIndex(blockRow, blockCol);
|
||||
|
||||
if (!BlockMap.TryGetValue(zIndex, out XTableBlock block))
|
||||
return;
|
||||
|
||||
// 移除包含此单元格的所有合并描述
|
||||
for (int i = block.MergeDescriptors.Count - 1; i >= 0; i--)
|
||||
// 1) 从这个单元格所在的块开始:移除包含此坐标的合并描述(被合并格)
|
||||
if (BlockMap.TryGetValue(zIndex, out XTableBlock block))
|
||||
{
|
||||
if (block.MergeDescriptors[i].Contains(localRow, localCol))
|
||||
for (int i = block.MergeDescriptors.Count - 1; i >= 0; i--)
|
||||
{
|
||||
block.MergeDescriptors.RemoveAt(i);
|
||||
if (block.MergeDescriptors[i].Contains(localRow, localCol))
|
||||
block.MergeDescriptors.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// 2) 遍历所有块:移除源坐标为此单元格的合并描述(合并源 / 锚点)
|
||||
// 处理非跨块和跨块两种情况
|
||||
foreach (var kv in BlockMap)
|
||||
{
|
||||
var b = kv.Value;
|
||||
if (b.MergeDescriptors.Count == 0) continue;
|
||||
|
||||
for (int i = b.MergeDescriptors.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var desc = b.MergeDescriptors[i];
|
||||
|
||||
// 非跨块:源在同一个块内 → 直接比较本地坐标
|
||||
if (!desc.IsCrossBlock &&
|
||||
desc.SourceLocalRow == localRow &&
|
||||
desc.SourceLocalCol == localCol &&
|
||||
kv.Key == zIndex)
|
||||
{
|
||||
b.MergeDescriptors.RemoveAt(i);
|
||||
}
|
||||
// 跨块:源在另一个块 → 比较 SourceBlockIndex + 源本地坐标
|
||||
else if (desc.IsCrossBlock &&
|
||||
desc.SourceBlockIndex == zIndex &&
|
||||
desc.SourceLocalRow == localRow &&
|
||||
desc.SourceLocalCol == localCol)
|
||||
{
|
||||
b.MergeDescriptors.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -301,9 +342,47 @@ namespace XericUI.XTable.Core
|
||||
|
||||
#region 查询方法
|
||||
|
||||
/// <summary>
|
||||
/// 判断指定块是否存在
|
||||
/// </summary>
|
||||
/// <summary>判断指定单元格是否被合并覆盖(非源,会被重定向)</summary>
|
||||
public bool IsCellMerged(int row, int 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 false;
|
||||
return block.GetMergeRedirect(localRow, localCol) != null;
|
||||
}
|
||||
|
||||
/// <summary>判断指定单元格是否为合并源(锚点),并返回合并跨度</summary>
|
||||
public bool IsMergeSource(int row, int col, out int rowSpan, out int colSpan)
|
||||
{
|
||||
rowSpan = 1; colSpan = 1;
|
||||
XTableCoordinateUtility.CellToBlockCoordinate(
|
||||
row, col, BlockSizeX, BlockSizeY,
|
||||
out int blockRow, out int blockCol,
|
||||
out int localRow, out int localCol);
|
||||
ulong thisZIndex = XTableBlockMapping.BlockCoordToZIndex(blockRow, blockCol);
|
||||
|
||||
foreach (var kv in BlockMap)
|
||||
{
|
||||
foreach (var desc in kv.Value.MergeDescriptors)
|
||||
{
|
||||
ulong srcBlockIdx = desc.IsCrossBlock ? desc.SourceBlockIndex : kv.Key;
|
||||
if (srcBlockIdx == thisZIndex &&
|
||||
desc.SourceLocalRow == localRow &&
|
||||
desc.SourceLocalCol == localCol)
|
||||
{
|
||||
rowSpan = desc.MergeRowSpan;
|
||||
colSpan = desc.MergeColSpan;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>判断指定块是否存在</summary>
|
||||
public bool HasBlock(int blockRow, int blockCol)
|
||||
{
|
||||
ulong zIndex = XTableBlockMapping.BlockCoordToZIndex(blockRow, blockCol);
|
||||
|
||||
@@ -310,6 +310,13 @@ namespace XericUI.XTable.Rendering.Component
|
||||
MarkDirty(TableDirtyType.DataChanged);
|
||||
}
|
||||
|
||||
/// <summary>判断指定单元格是否被合并覆盖(非源,会被重定向)</summary>
|
||||
public bool IsCellMerged(int row, int col) => TableData.IsCellMerged(row, col);
|
||||
|
||||
/// <summary>判断指定单元格是否为合并源(锚点),并返回合并跨度</summary>
|
||||
public bool IsMergeSource(int row, int col, out int rowSpan, out int colSpan)
|
||||
=> TableData.IsMergeSource(row, col, out rowSpan, out colSpan);
|
||||
|
||||
/// <summary>在末尾追加一行,默认行高 40</summary>
|
||||
public void AddRow(float height = 40f)
|
||||
{
|
||||
@@ -738,15 +745,28 @@ namespace XericUI.XTable.Rendering.Component
|
||||
{
|
||||
for (int c = sc; c < ec && c < m_ColWidths.Length; c++)
|
||||
{
|
||||
// 跳过被合并覆盖的单元格
|
||||
if (TableData.IsCellMerged(r, c)) continue;
|
||||
|
||||
float cellX = GetColLeftX(c);
|
||||
float cellY = -GetRowTopY(r);
|
||||
float cellW = m_ColWidths[c];
|
||||
float cellH = m_RowHeights[r];
|
||||
|
||||
// 合并源:扩展尺寸
|
||||
if (TableData.IsMergeSource(r, c, out int mergeRS, out int mergeCS))
|
||||
{
|
||||
for (int i = 1; i < mergeCS && c + i < m_ColWidths.Length; i++)
|
||||
cellW += m_ColWidths[c + i];
|
||||
for (int i = 1; i < mergeRS && r + i < m_RowHeights.Length; i++)
|
||||
cellH += m_RowHeights[r + i];
|
||||
}
|
||||
|
||||
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");
|
||||
@@ -763,13 +783,13 @@ namespace XericUI.XTable.Rendering.Component
|
||||
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);
|
||||
@@ -802,10 +822,23 @@ namespace XericUI.XTable.Rendering.Component
|
||||
{
|
||||
for (int c = sc; c < ec && c < m_ColWidths.Length; c++)
|
||||
{
|
||||
// 跳过被合并覆盖的单元格
|
||||
if (TableData.IsCellMerged(r, c)) continue;
|
||||
|
||||
float cellX = GetColLeftX(c);
|
||||
float cellY = -GetRowTopY(r);
|
||||
float cellW = m_ColWidths[c];
|
||||
float cellH = m_RowHeights[r];
|
||||
|
||||
// 合并源:扩展尺寸
|
||||
if (TableData.IsMergeSource(r, c, out int mergeRS, out int mergeCS))
|
||||
{
|
||||
for (int i = 1; i < mergeCS && c + i < m_ColWidths.Length; i++)
|
||||
cellW += m_ColWidths[c + i];
|
||||
for (int i = 1; i < mergeRS && r + i < m_RowHeights.Length; i++)
|
||||
cellH += m_RowHeights[r + i];
|
||||
}
|
||||
|
||||
XTableCellData data = TableData.GetCell(r, c);
|
||||
string cellNS = (data != null && !string.IsNullOrEmpty(data.StyleNamespace))
|
||||
? data.StyleNamespace : ns;
|
||||
|
||||
Reference in New Issue
Block a user