换成不触发active的对象池队列模式
This commit is contained in:
@@ -37,10 +37,6 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
#region 字段
|
||||
|
||||
private Transform m_Parent;
|
||||
private Transform m_PoolRoot;
|
||||
|
||||
/// <summary>池根节点(所有回收对象均挂在此节点下,节点本身处于 inactive)</summary>
|
||||
public Transform PoolRoot => m_PoolRoot;
|
||||
|
||||
/// <summary>运行时的默认样式命名空间(编辑器下为 null,不绑定)</summary>
|
||||
private string m_DefaultStyleNamespace;
|
||||
@@ -48,14 +44,20 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
/// <summary>所有已绑定的 StyleBoundElement 回调集合(用于样式变更时通知外部)</summary>
|
||||
public event System.Action OnStyleChangeDetected;
|
||||
|
||||
private Stack<PooledImage> m_ImagePool = new Stack<PooledImage>();
|
||||
private Stack<PooledText> m_TextPool = new Stack<PooledText>();
|
||||
private Queue<PooledImage> m_ImagePool = new Queue<PooledImage>();
|
||||
private Queue<PooledText> m_TextPool = new Queue<PooledText>();
|
||||
private List<PooledImage> m_ActiveImages = new List<PooledImage>();
|
||||
private List<PooledText> m_ActiveTexts = new List<PooledText>();
|
||||
|
||||
/// <summary>HideFlags 应用于所有动态创建的对象(不保存、不在 Hierarchy 显示)</summary>
|
||||
private const HideFlags POOL_FLAGS = HideFlags.DontSave | HideFlags.HideInHierarchy;
|
||||
|
||||
/// <summary>渲染项目总数上限,超出后 GetImage/GetText 返回 null 并发出警告</summary>
|
||||
private const int MAX_POOL_ITEMS = 256;
|
||||
|
||||
private int m_ImageCreatedCount;
|
||||
private int m_TextCreatedCount;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 构造函数与析构
|
||||
@@ -64,12 +66,6 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
{
|
||||
m_Parent = parent;
|
||||
m_DefaultStyleNamespace = defaultStyleNamespace;
|
||||
|
||||
GameObject poolRoot = new GameObject("_CellPool");
|
||||
poolRoot.hideFlags = POOL_FLAGS;
|
||||
poolRoot.transform.SetParent(parent, false);
|
||||
poolRoot.SetActive(false);
|
||||
m_PoolRoot = poolRoot.transform;
|
||||
}
|
||||
|
||||
/// <summary>彻底销毁所有池对象(包括活跃和休眠的)</summary>
|
||||
@@ -91,18 +87,11 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
// 杀死池中对象
|
||||
while (m_ImagePool.Count > 0)
|
||||
{
|
||||
KillObject(m_ImagePool.Pop().Root);
|
||||
KillObject(m_ImagePool.Dequeue().Root);
|
||||
}
|
||||
while (m_TextPool.Count > 0)
|
||||
{
|
||||
KillObject(m_TextPool.Pop().Root);
|
||||
}
|
||||
|
||||
// 杀死池根
|
||||
if (m_PoolRoot != null)
|
||||
{
|
||||
KillObject(m_PoolRoot.gameObject);
|
||||
m_PoolRoot = null;
|
||||
KillObject(m_TextPool.Dequeue().Root);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,14 +121,18 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
PooledImage item;
|
||||
if (m_ImagePool.Count > 0)
|
||||
{
|
||||
item = m_ImagePool.Pop();
|
||||
item.Root.SetActive(true);
|
||||
item.Root.transform.SetParent(m_Parent, false);
|
||||
item = m_ImagePool.Dequeue();
|
||||
ResetImageDefaults(item);
|
||||
}
|
||||
else if (m_ImageCreatedCount < MAX_POOL_ITEMS)
|
||||
{
|
||||
item = CreateImage(name);
|
||||
m_ImageCreatedCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
item = CreateImage(name);
|
||||
Debug.LogWarning($"[XericUIActionTable] Image 池已达上限 {MAX_POOL_ITEMS},无法分配新对象");
|
||||
return null;
|
||||
}
|
||||
BindStyle(item.Style, styleNamespace);
|
||||
m_ActiveImages.Add(item);
|
||||
@@ -151,14 +144,18 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
PooledText item;
|
||||
if (m_TextPool.Count > 0)
|
||||
{
|
||||
item = m_TextPool.Pop();
|
||||
item.Root.SetActive(true);
|
||||
item.Root.transform.SetParent(m_Parent, false);
|
||||
item = m_TextPool.Dequeue();
|
||||
ResetTextDefaults(item);
|
||||
}
|
||||
else if (m_TextCreatedCount < MAX_POOL_ITEMS)
|
||||
{
|
||||
item = CreateText(name);
|
||||
m_TextCreatedCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
item = CreateText(name);
|
||||
Debug.LogWarning($"[XericUIActionTable] Text 池已达上限 {MAX_POOL_ITEMS},无法分配新对象");
|
||||
return null;
|
||||
}
|
||||
BindStyle(item.Style, styleNamespace);
|
||||
m_ActiveTexts.Add(item);
|
||||
@@ -214,18 +211,13 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
private void ReturnImage(PooledImage item)
|
||||
{
|
||||
item.Style?.Unbind();
|
||||
item.Root.SetActive(false);
|
||||
item.Root.transform.SetParent(m_PoolRoot, false);
|
||||
m_ImagePool.Push(item);
|
||||
m_ImagePool.Enqueue(item);
|
||||
}
|
||||
|
||||
private void ReturnText(PooledText item)
|
||||
{
|
||||
item.Style?.Unbind();
|
||||
item.Text.text = "";
|
||||
item.Root.SetActive(false);
|
||||
item.Root.transform.SetParent(m_PoolRoot, false);
|
||||
m_TextPool.Push(item);
|
||||
m_TextPool.Enqueue(item);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -251,7 +243,7 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
item.Rect.pivot = PIVOT_TOPLEFT;
|
||||
item.Rect.anchoredPosition = Vector2.zero;
|
||||
item.Rect.sizeDelta = Vector2.zero;
|
||||
item.Text.text = "";
|
||||
item.Text.SetText(string.Empty);
|
||||
item.Text.color = Color.black;
|
||||
item.Text.fontSize = 14;
|
||||
item.Text.alignment = TextAlignmentOptions.Midline;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Pool;
|
||||
|
||||
namespace XericUI.XTable.Rendering.Elements
|
||||
{
|
||||
/// <summary>
|
||||
/// 预制体对象池——按原型分组管理,每个预制体对应一个独立的对象池。
|
||||
/// 使用 Stack + HashSet 模式与 <see cref="CellAssembler"/> 保持一致。
|
||||
/// 使用 Queue + HashSet 模式,FIFO 保证对象按回收顺序均匀复用。
|
||||
/// </summary>
|
||||
public class PrefabPrototypePool
|
||||
{
|
||||
@@ -16,8 +15,8 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
private class PrefabPool
|
||||
{
|
||||
public GameObject Prototype;
|
||||
/// <summary>休眠实例栈(池满时先归还的优先复用)</summary>
|
||||
public Stack<GameObject> Available = new Stack<GameObject>();
|
||||
/// <summary>休眠实例队列(FIFO,先归还的优先复用)</summary>
|
||||
public Queue<GameObject> Available = new Queue<GameObject>();
|
||||
/// <summary>活跃实例集合(O(1) 查找 + 防止重复归还)</summary>
|
||||
public HashSet<GameObject> Active = new HashSet<GameObject>();
|
||||
}
|
||||
@@ -28,10 +27,10 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
|
||||
private Dictionary<GameObject, PrefabPool> m_Pools = new Dictionary<GameObject, PrefabPool>();
|
||||
private Transform m_Parent;
|
||||
private Transform m_PoolRoot;
|
||||
|
||||
/// <summary>池根节点(所有回收对象均挂在此节点下,节点本身处于 inactive)</summary>
|
||||
public Transform PoolRoot => m_PoolRoot;
|
||||
/// <summary>渲染项目总数上限</summary>
|
||||
private const int MAX_PREFAB_ITEMS = 256;
|
||||
private int m_TotalCreated;
|
||||
|
||||
private const HideFlags POOL_FLAGS = HideFlags.DontSave | HideFlags.HideInHierarchy;
|
||||
|
||||
@@ -45,15 +44,9 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
public PrefabPrototypePool(Transform parent)
|
||||
{
|
||||
m_Parent = parent;
|
||||
|
||||
GameObject poolRoot = new GameObject("_PrefabPoolRoot");
|
||||
poolRoot.hideFlags = POOL_FLAGS;
|
||||
poolRoot.transform.SetParent(parent, false);
|
||||
poolRoot.SetActive(false);
|
||||
m_PoolRoot = poolRoot.transform;
|
||||
}
|
||||
|
||||
/// <summary>彻底销毁所有池对象(活跃 + 休眠 + 池根)</summary>
|
||||
/// <summary>彻底销毁所有池对象(活跃 + 休眠)</summary>
|
||||
public void DestroyAll()
|
||||
{
|
||||
foreach (var kv in m_Pools)
|
||||
@@ -65,15 +58,9 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
pool.Active.Clear();
|
||||
// 销毁休眠实例
|
||||
while (pool.Available.Count > 0)
|
||||
KillObject(pool.Available.Pop());
|
||||
KillObject(pool.Available.Dequeue());
|
||||
}
|
||||
m_Pools.Clear();
|
||||
|
||||
if (m_PoolRoot != null)
|
||||
{
|
||||
KillObject(m_PoolRoot.gameObject);
|
||||
m_PoolRoot = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void KillObject(GameObject go)
|
||||
@@ -89,7 +76,7 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
|
||||
#region 池操作
|
||||
|
||||
/// <summary>从池中获取实例(池空则 Instantiate 新的)</summary>
|
||||
/// <summary>从池中获取实例(FIFO 复用;池空且未达上限则 Instantiate;已达上限返回 null)</summary>
|
||||
public GameObject Acquire(GameObject prefab, int row, int col)
|
||||
{
|
||||
if (prefab == null) return null;
|
||||
@@ -99,14 +86,18 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
GameObject instance;
|
||||
if (pool.Available.Count > 0)
|
||||
{
|
||||
instance = pool.Available.Pop();
|
||||
instance.SetActive(true);
|
||||
instance.transform.SetParent(m_Parent, false);
|
||||
instance = pool.Available.Dequeue();
|
||||
}
|
||||
else
|
||||
else if (m_TotalCreated < MAX_PREFAB_ITEMS)
|
||||
{
|
||||
instance = Object.Instantiate(prefab, m_Parent);
|
||||
instance.hideFlags = POOL_FLAGS;
|
||||
m_TotalCreated++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"[XericUIActionTable] Prefab 池已达上限 {MAX_PREFAB_ITEMS},无法分配新实例");
|
||||
return null;
|
||||
}
|
||||
|
||||
instance.name = $"_prefab_{row}_{col}";
|
||||
@@ -122,7 +113,7 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>将指定实例归还对象池(Deactivate + 移入 PoolRoot)</summary>
|
||||
/// <summary>将指定实例归还对象池(不入池根,原地保留避免 OnEnable/OnDisable)</summary>
|
||||
public void Release(GameObject instance)
|
||||
{
|
||||
if (instance == null) return;
|
||||
@@ -132,9 +123,7 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
{
|
||||
if (kv.Value.Active.Remove(instance))
|
||||
{
|
||||
instance.SetActive(false);
|
||||
instance.transform.SetParent(m_PoolRoot, false);
|
||||
kv.Value.Available.Push(instance);
|
||||
kv.Value.Available.Enqueue(instance);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -143,7 +132,7 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
KillObject(instance);
|
||||
}
|
||||
|
||||
/// <summary>将所有活跃实例回收至池</summary>
|
||||
/// <summary>将所有活跃实例回收至池(原地保留,仅从活跃集移除并入队)</summary>
|
||||
public void ReturnAll()
|
||||
{
|
||||
foreach (var kv in m_Pools)
|
||||
@@ -151,9 +140,7 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
var pool = kv.Value;
|
||||
foreach (var go in pool.Active)
|
||||
{
|
||||
go.SetActive(false);
|
||||
go.transform.SetParent(m_PoolRoot, false);
|
||||
pool.Available.Push(go);
|
||||
pool.Available.Enqueue(go);
|
||||
}
|
||||
pool.Active.Clear();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user