表格设置单元格为预制体的情况下不会刷新这个预制体,因为条件写反了。
This commit is contained in:
@@ -90,22 +90,13 @@ namespace XericUI.XTable.Rendering.Component
|
||||
sc = Mathf.Max(sc, StartCol);
|
||||
er = Mathf.Min(er, EndRow > 0 ? EndRow : rows.Length);
|
||||
ec = Mathf.Min(ec, EndCol > 0 ? EndCol : cols.Length);
|
||||
if (sr >= er || sc >= ec)
|
||||
{
|
||||
if (fullRefresh) ReleaseAll();
|
||||
return;
|
||||
}
|
||||
if (sr >= er || sc >= ec) return;
|
||||
|
||||
var target = new HashSet<(int, int)>();
|
||||
for (int r = sr; r < er; r++)
|
||||
for (int c = sc; c < ec; c++)
|
||||
target.Add((r, c));
|
||||
|
||||
if (fullRefresh)
|
||||
ReleaseAll();
|
||||
else
|
||||
ReleaseExcept(target);
|
||||
|
||||
foreach (var cell in target)
|
||||
if (fullRefresh || !m_Rendered.Contains(cell))
|
||||
RenderCell(cell.Item1, cell.Item2, rows, cols, editorMode);
|
||||
@@ -122,18 +113,6 @@ namespace XericUI.XTable.Rendering.Component
|
||||
m_Rendered.Clear();
|
||||
}
|
||||
|
||||
private void ReleaseExcept(HashSet<(int, int)> target)
|
||||
{
|
||||
var remove = new List<(int, int)>();
|
||||
foreach (var pair in m_Tracked)
|
||||
if (!target.Contains(pair.Key)) remove.Add(pair.Key);
|
||||
foreach (var key in remove)
|
||||
{
|
||||
ReleaseTracked(m_Tracked[key]);
|
||||
m_Tracked.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseTracked(Tracked tracked)
|
||||
{
|
||||
Assembler.ReleaseText(tracked.Text);
|
||||
@@ -191,15 +170,20 @@ namespace XericUI.XTable.Rendering.Component
|
||||
}
|
||||
else if (cell.ContentType == CellContentType.Prefab && cell.Prefab != null && PrefabPool != null)
|
||||
{
|
||||
var prefab = PrefabPool.Acquire(cell.Prefab, cellId, m_Parent);
|
||||
var key = (row, col);
|
||||
GameObject activePrefab = null;
|
||||
bool wasActive = ActivePrefabMap != null
|
||||
&& ActivePrefabMap.TryGetValue(key, out activePrefab);
|
||||
var prefab = wasActive ? activePrefab : PrefabPool.Acquire(cell.Prefab, cellId, m_Parent);
|
||||
if (prefab != null)
|
||||
{
|
||||
var rt = prefab.GetComponent<RectTransform>();
|
||||
rt.anchoredPosition = new Vector2(x, y);
|
||||
rt.sizeDelta = new Vector2(width, height);
|
||||
if (ActivePrefabMap != null)
|
||||
ActivePrefabMap[(row, col)] = prefab;
|
||||
cell.OnPrefabAcquire?.Invoke(prefab);
|
||||
ActivePrefabMap[key] = prefab;
|
||||
if (!wasActive)
|
||||
cell.OnPrefabAcquire?.Invoke(prefab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,7 +452,9 @@ namespace XericUI.XTable.Rendering.Component
|
||||
public void RemoveRow(int row)
|
||||
{
|
||||
if (TryEnqueueUpdateCommand(new UpdateCommand(UpdateCommandType.RemoveRow, row))) return;
|
||||
var prefabCallbacks = CaptureActivePrefabReleaseCallbacks();
|
||||
RemoveRowImmediate(row);
|
||||
RebuildRenderBindings(prefabCallbacks);
|
||||
}
|
||||
|
||||
private void RemoveRowImmediate(int row)
|
||||
@@ -509,7 +511,9 @@ namespace XericUI.XTable.Rendering.Component
|
||||
public void RemoveColumn(int col)
|
||||
{
|
||||
if (TryEnqueueUpdateCommand(new UpdateCommand(UpdateCommandType.RemoveColumn, col: col))) return;
|
||||
var prefabCallbacks = CaptureActivePrefabReleaseCallbacks();
|
||||
RemoveColumnImmediate(col);
|
||||
RebuildRenderBindings(prefabCallbacks);
|
||||
}
|
||||
|
||||
private void RemoveColumnImmediate(int col)
|
||||
@@ -762,26 +766,16 @@ namespace XericUI.XTable.Rendering.Component
|
||||
public void ClearData()
|
||||
{
|
||||
ThrowIfCheckingUpdate(nameof(ClearData));
|
||||
var prefabCallbacks = CaptureActivePrefabReleaseCallbacks();
|
||||
if (m_TableData != null)
|
||||
{
|
||||
// 清理预制体:先调用 OnPrefabRelease 再清理映射
|
||||
if (m_ActivePrefabMap != null)
|
||||
{
|
||||
foreach (var kv in m_ActivePrefabMap)
|
||||
{
|
||||
var cellData = m_TableData.GetCell(kv.Key.Item1, kv.Key.Item2);
|
||||
cellData?.OnPrefabRelease?.Invoke(kv.Value);
|
||||
}
|
||||
m_ActivePrefabMap.Clear();
|
||||
}
|
||||
m_PrefabPool?.ReturnAll();
|
||||
|
||||
m_TableData.ClearAllMerges();
|
||||
m_TableData.BlockMap.Clear();
|
||||
m_StyleNamespaceDirty = true;
|
||||
}
|
||||
m_Quadtree?.Clear();
|
||||
ClearSelection();
|
||||
RebuildRenderBindings(prefabCallbacks);
|
||||
MarkDirty(TableDirtyType.DataChanged);
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ namespace XericUI.XTable.Rendering.Component
|
||||
{
|
||||
Assembler = m_Assembler,
|
||||
PrefabPool = m_PrefabPool,
|
||||
ActivePrefabMap = m_ActivePrefabMap,
|
||||
CellPadding = CellPadding,
|
||||
Config = Config,
|
||||
SelectionTable = this,
|
||||
|
||||
@@ -19,11 +19,12 @@ namespace XericUI.XTable.Rendering.Component
|
||||
|
||||
/// <summary>可复用列表,避免每帧分配 GC</summary>
|
||||
[NonSerialized] private List<(int, int)> m_ReusableCellList = new(capacity: 128);
|
||||
|
||||
[NonSerialized] private List<QuadrantResult> m_ReusableQuadrants = new(capacity: 32);
|
||||
|
||||
/// <summary>控制滚动时是否使用四叉树(大表格推荐)</summary>
|
||||
private bool UseQuadtreeForScroll => m_Quadtree != null && m_Quadtree.IsBuilt
|
||||
&& m_RowHeights.Length * m_ColWidths.Length > 2000;
|
||||
&& m_RowHeights.Length * m_ColWidths.Length > 2000;
|
||||
|
||||
private struct CellTrackedObjs
|
||||
{
|
||||
@@ -52,6 +53,7 @@ namespace XericUI.XTable.Rendering.Component
|
||||
m_Assembler?.ReleaseText(objs.CellText);
|
||||
m_Assembler?.ReleaseImage(objs.CellImage);
|
||||
}
|
||||
|
||||
m_CellTracked.Clear();
|
||||
m_LastRenderedCells.Clear();
|
||||
}
|
||||
@@ -212,13 +214,19 @@ namespace XericUI.XTable.Rendering.Component
|
||||
{
|
||||
if (data.Prefab == null) return;
|
||||
|
||||
GameObject instance = m_PrefabPool.Acquire(data.Prefab, cellId);
|
||||
var key = (row, col);
|
||||
GameObject instance = null;
|
||||
bool wasActive = m_ActivePrefabMap != null
|
||||
&& m_ActivePrefabMap.TryGetValue(key, out instance);
|
||||
if (!wasActive)
|
||||
instance = m_PrefabPool.Acquire(data.Prefab, cellId);
|
||||
if (instance == null) return;
|
||||
RectTransform prt = instance.GetComponent<RectTransform>();
|
||||
prt.anchoredPosition = new Vector2(cellX, cellY);
|
||||
prt.sizeDelta = new Vector2(cellW, cellH);
|
||||
m_ActivePrefabMap[(row, col)] = instance;
|
||||
data.OnPrefabAcquire?.Invoke(instance);
|
||||
m_ActivePrefabMap[key] = instance;
|
||||
if (!wasActive)
|
||||
data.OnPrefabAcquire?.Invoke(instance);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -227,6 +235,8 @@ namespace XericUI.XTable.Rendering.Component
|
||||
|
||||
private void ReleaseRenderedBindings(Dictionary<GameObject, System.Action<GameObject>> prefabReleaseCallbacks = null)
|
||||
{
|
||||
// 结构重建必须解除所有 cellId 映射;不能只依赖当前可见区域的 tracked 集合。
|
||||
m_Assembler?.ReleaseAllBindings();
|
||||
ReleaseAllTrackedCells();
|
||||
ReleaseFrozenCells();
|
||||
m_LastRenderedCells.Clear();
|
||||
@@ -238,6 +248,12 @@ namespace XericUI.XTable.Rendering.Component
|
||||
m_ActivePrefabMap?.Clear();
|
||||
}
|
||||
|
||||
/// <summary>结构删除后的唯一绑定重建入口;普通刷新和滚动不得调用。</summary>
|
||||
private void RebuildRenderBindings(Dictionary<GameObject, System.Action<GameObject>> prefabReleaseCallbacks)
|
||||
{
|
||||
ReleaseRenderedBindings(prefabReleaseCallbacks);
|
||||
}
|
||||
|
||||
public void RefreshView(bool releaseBindings = true)
|
||||
{
|
||||
TableDirtyType refreshedFlags = m_DirtyFlag.Flags;
|
||||
@@ -271,9 +287,6 @@ namespace XericUI.XTable.Rendering.Component
|
||||
|
||||
UpdateBackground();
|
||||
|
||||
if (releaseBindings)
|
||||
ReleaseRenderedBindings(CaptureActivePrefabReleaseCallbacks());
|
||||
|
||||
// 清理孤立子对象
|
||||
CleanOrphanChildren();
|
||||
|
||||
@@ -334,32 +347,9 @@ namespace XericUI.XTable.Rendering.Component
|
||||
var newVisible = new HashSet<(int, int)>();
|
||||
ComputeVisibleCellsScrollInto(newVisible);
|
||||
|
||||
// 2. 回收不再可见的追踪对象
|
||||
m_ReusableCellList.Clear();
|
||||
foreach (var cell in m_LastRenderedCells)
|
||||
if (!newVisible.Contains(cell))
|
||||
m_ReusableCellList.Add(cell);
|
||||
foreach (var cell in m_ReusableCellList)
|
||||
ReleaseTrackedCell(cell.Item1, cell.Item2);
|
||||
// 2. 离屏单元格保持其绑定,供后续重绘直接复用。
|
||||
|
||||
// 3. 回收不再可见的预制体(仅从映射表移除,预制体保留在计数器槽位中复用)
|
||||
if (m_ActivePrefabMap != null && m_ActivePrefabMap.Count > 0)
|
||||
{
|
||||
m_ReusableCellList.Clear();
|
||||
foreach (var kv in m_ActivePrefabMap)
|
||||
if (!newVisible.Contains(kv.Key))
|
||||
m_ReusableCellList.Add(kv.Key);
|
||||
|
||||
foreach (var key in m_ReusableCellList)
|
||||
{
|
||||
GameObject instance = m_ActivePrefabMap[key];
|
||||
var data = TableData.GetCell(key.Item1, key.Item2);
|
||||
m_PrefabPool?.Release(instance, data?.OnPrefabRelease);
|
||||
m_ActivePrefabMap.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 渲染单元格:选区变更时全量重渲所有可见单元格,否则仅新进入的
|
||||
// 3. 渲染单元格:选区变更时全量重渲所有可见单元格,否则仅新进入的
|
||||
foreach (var cell in newVisible)
|
||||
{
|
||||
if (!m_LastRenderedCells.Contains(cell))
|
||||
@@ -411,7 +401,8 @@ namespace XericUI.XTable.Rendering.Component
|
||||
if (m_BackgroundRenderer != null) return;
|
||||
|
||||
var backgroundGo = new GameObject("_TableBackground",
|
||||
typeof(RectTransform), typeof(CanvasRenderer), typeof(XTableBackgroundRenderer), typeof(XTableSelectionInput));
|
||||
typeof(RectTransform), typeof(CanvasRenderer), typeof(XTableBackgroundRenderer),
|
||||
typeof(XTableSelectionInput));
|
||||
backgroundGo.hideFlags = HideFlags.DontSave | HideFlags.HideInHierarchy;
|
||||
backgroundGo.transform.SetParent(ContentTransform, false);
|
||||
backgroundGo.transform.SetAsFirstSibling();
|
||||
@@ -451,7 +442,8 @@ namespace XericUI.XTable.Rendering.Component
|
||||
{
|
||||
if (string.IsNullOrEmpty(quadrant.Namespace) || quadrant.Namespace == baseNamespace)
|
||||
continue;
|
||||
rects.Add(new XTableBackgroundRenderer.RectData(quadrant.Region, GetCellBgColor(quadrant.Namespace)));
|
||||
rects.Add(new XTableBackgroundRenderer.RectData(quadrant.Region,
|
||||
GetCellBgColor(quadrant.Namespace)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -474,4 +466,4 @@ namespace XericUI.XTable.Rendering.Component
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,17 +72,20 @@ namespace XericUI.XTable.Rendering.Component
|
||||
private sealed class UpdateContext
|
||||
{
|
||||
public TableDirtyType DirtyFlags;
|
||||
public bool RequiresBindingRebuild;
|
||||
public readonly List<UpdateCommand> Commands = new();
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
DirtyFlags = TableDirtyType.None;
|
||||
RequiresBindingRebuild = false;
|
||||
Commands.Clear();
|
||||
}
|
||||
|
||||
public void MergeFrom(UpdateContext child)
|
||||
{
|
||||
DirtyFlags |= child.DirtyFlags;
|
||||
RequiresBindingRebuild |= child.RequiresBindingRebuild;
|
||||
Commands.AddRange(child.Commands);
|
||||
}
|
||||
}
|
||||
@@ -134,7 +137,10 @@ namespace XericUI.XTable.Rendering.Component
|
||||
private bool TryEnqueueUpdateCommand(UpdateCommand command)
|
||||
{
|
||||
if (!IsCheckingUpdate) return false;
|
||||
m_UpdateContextStack.Peek().Commands.Add(command);
|
||||
UpdateContext context = m_UpdateContextStack.Peek();
|
||||
context.Commands.Add(command);
|
||||
context.RequiresBindingRebuild |= command.Type == UpdateCommandType.RemoveRow
|
||||
|| command.Type == UpdateCommandType.RemoveColumn;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -158,12 +164,14 @@ namespace XericUI.XTable.Rendering.Component
|
||||
m_UpdateContextStack.Push(context);
|
||||
try
|
||||
{
|
||||
Dictionary<GameObject, Action<GameObject>> prefabCallbacks = CaptureActivePrefabReleaseCallbacks();
|
||||
Dictionary<GameObject, Action<GameObject>> prefabCallbacks = context.RequiresBindingRebuild
|
||||
? CaptureActivePrefabReleaseCallbacks() : null;
|
||||
ExecuteUpdateCommands(context);
|
||||
if (context.DirtyFlags == TableDirtyType.None) return;
|
||||
|
||||
m_UpdateContextStack.Pop();
|
||||
ReleaseRenderedBindings(prefabCallbacks);
|
||||
if (context.RequiresBindingRebuild)
|
||||
RebuildRenderBindings(prefabCallbacks);
|
||||
ApplyDirty(context.DirtyFlags);
|
||||
RefreshView(false);
|
||||
RefreshSelectionOverlays();
|
||||
|
||||
Reference in New Issue
Block a user