将可配置参数开放到界面上。
This commit is contained in:
@@ -22,12 +22,19 @@ namespace XericUIEditor.XTable
|
||||
private SerializedProperty m_ColWidthsProp;
|
||||
private SerializedProperty m_DefaultStyleNsProp;
|
||||
private SerializedProperty m_ScrollRectProp;
|
||||
private SerializedProperty m_ConfigProp;
|
||||
private SerializedProperty m_EnableSelectionAutoScrollProp;
|
||||
private SerializedProperty m_SelectionAutoScrollEdgeThresholdProp;
|
||||
private SerializedProperty m_SelectionAutoScrollMaxSpeedProp;
|
||||
private SerializedProperty m_SelectionAutoScrollAccelerationProp;
|
||||
|
||||
internal const string MENU_PATH = "GameObject/Xeric Library/Table/Xeric UI Action Table";
|
||||
|
||||
// 折叠状态
|
||||
private static bool s_StyleFoldout = true;
|
||||
private static bool s_SizeFoldout = true;
|
||||
private static bool s_ConfigFoldout = true;
|
||||
private static bool s_InteractionFoldout = true;
|
||||
private static bool s_DebugFoldout;
|
||||
private static bool s_DataBrowseFoldout;
|
||||
|
||||
@@ -42,6 +49,11 @@ namespace XericUIEditor.XTable
|
||||
m_ColWidthsProp = serializedObject.FindProperty("m_ColWidths");
|
||||
m_DefaultStyleNsProp = serializedObject.FindProperty("m_DefaultStyleNamespace");
|
||||
m_ScrollRectProp = serializedObject.FindProperty("m_ScrollRect");
|
||||
m_ConfigProp = serializedObject.FindProperty("m_Config");
|
||||
m_EnableSelectionAutoScrollProp = serializedObject.FindProperty("m_EnableSelectionAutoScroll");
|
||||
m_SelectionAutoScrollEdgeThresholdProp = serializedObject.FindProperty("m_SelectionAutoScrollEdgeThreshold");
|
||||
m_SelectionAutoScrollMaxSpeedProp = serializedObject.FindProperty("m_SelectionAutoScrollMaxSpeed");
|
||||
m_SelectionAutoScrollAccelerationProp = serializedObject.FindProperty("m_SelectionAutoScrollAcceleration");
|
||||
|
||||
// 同步表格的 ChildrenVisible 状态到编辑器 toggle
|
||||
m_ShowChildren = m_Table.ChildrenVisible;
|
||||
@@ -85,6 +97,36 @@ namespace XericUIEditor.XTable
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
// ===== 配置 =====
|
||||
EditorGUILayout.Space(4);
|
||||
s_ConfigFoldout = EditorGUILayout.Foldout(s_ConfigFoldout, "配置", true);
|
||||
if (s_ConfigFoldout)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
if (m_ConfigProp != null)
|
||||
EditorGUILayout.PropertyField(m_ConfigProp, new GUIContent("表格配置"));
|
||||
if (m_ConfigProp == null || m_ConfigProp.objectReferenceValue == null)
|
||||
EditorGUILayout.HelpBox("未指定配置资源,将在运行时加载默认配置。", MessageType.Info);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
// ===== 交互 =====
|
||||
EditorGUILayout.Space(4);
|
||||
s_InteractionFoldout = EditorGUILayout.Foldout(s_InteractionFoldout, "交互", true);
|
||||
if (s_InteractionFoldout)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
if (m_EnableSelectionAutoScrollProp != null)
|
||||
EditorGUILayout.PropertyField(m_EnableSelectionAutoScrollProp, new GUIContent("启用选择自动滚动"));
|
||||
if (m_SelectionAutoScrollEdgeThresholdProp != null)
|
||||
EditorGUILayout.PropertyField(m_SelectionAutoScrollEdgeThresholdProp, new GUIContent("自动滚动边缘阈值"));
|
||||
if (m_SelectionAutoScrollMaxSpeedProp != null)
|
||||
EditorGUILayout.PropertyField(m_SelectionAutoScrollMaxSpeedProp, new GUIContent("自动滚动最大速度"));
|
||||
if (m_SelectionAutoScrollAccelerationProp != null)
|
||||
EditorGUILayout.PropertyField(m_SelectionAutoScrollAccelerationProp, new GUIContent("自动滚动加速度指数"));
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
// ===== 调试 =====
|
||||
EditorGUILayout.Space(4);
|
||||
s_DebugFoldout = EditorGUILayout.Foldout(s_DebugFoldout, "调试", true);
|
||||
|
||||
@@ -35,8 +35,17 @@ namespace XericUI.XTable.Core
|
||||
#region 对象池
|
||||
|
||||
[Header("对象池")]
|
||||
[Tooltip("通用对象池初始容量")]
|
||||
public int PoolInitialCapacity = 64;
|
||||
[Min(1)]
|
||||
[Tooltip("文本池允许创建的对象总上限")]
|
||||
public int TextPoolMaxCapacity = 256;
|
||||
|
||||
[Min(1)]
|
||||
[Tooltip("图片池允许创建的对象总上限")]
|
||||
public int ImagePoolMaxCapacity = 256;
|
||||
|
||||
[Min(1)]
|
||||
[Tooltip("预制体池允许创建的实例总上限")]
|
||||
public int PrefabPoolMaxCapacity = 256;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -669,8 +669,7 @@ namespace XericUI.XTable.Rendering.Component
|
||||
m_QuadtreeDirty = true;
|
||||
m_StyleNamespaceDirty = true;
|
||||
|
||||
m_Assembler = new CellAssembler(ContentTransform, m_DefaultStyleNamespace);
|
||||
m_PrefabPool = new PrefabPrototypePool(ContentTransform);
|
||||
CreatePools();
|
||||
m_ActivePrefabMap = new Dictionary<(int, int), GameObject>();
|
||||
UpdateResolvedCellSizes();
|
||||
RecalculateTotalSize();
|
||||
@@ -730,8 +729,7 @@ namespace XericUI.XTable.Rendering.Component
|
||||
m_QuadtreeDirty = true;
|
||||
m_StyleNamespaceDirty = true;
|
||||
|
||||
m_Assembler = new CellAssembler(ContentTransform, m_DefaultStyleNamespace);
|
||||
m_PrefabPool = new PrefabPrototypePool(ContentTransform);
|
||||
CreatePools();
|
||||
m_ActivePrefabMap = new Dictionary<(int, int), GameObject>();
|
||||
UpdateResolvedCellSizes();
|
||||
RecalculateTotalSize();
|
||||
@@ -818,8 +816,7 @@ namespace XericUI.XTable.Rendering.Component
|
||||
m_StyleNamespaceDirty = true;
|
||||
ClearSelection();
|
||||
|
||||
m_Assembler = new CellAssembler(ContentTransform, m_DefaultStyleNamespace);
|
||||
m_PrefabPool = new PrefabPrototypePool(ContentTransform);
|
||||
CreatePools();
|
||||
m_ActivePrefabMap = new Dictionary<(int, int), GameObject>();
|
||||
MarkDirty(TableDirtyType.All);
|
||||
UpdateResolvedCellSizes();
|
||||
|
||||
@@ -261,7 +261,8 @@ namespace XericUI.XTable.Rendering.Component
|
||||
if (m_Assembler == null)
|
||||
{
|
||||
if (rectTransform != null)
|
||||
m_Assembler = new CellAssembler(ContentTransform, m_DefaultStyleNamespace);
|
||||
m_Assembler = new CellAssembler(ContentTransform, m_DefaultStyleNamespace,
|
||||
Config.TextPoolMaxCapacity, Config.ImagePoolMaxCapacity);
|
||||
else return;
|
||||
}
|
||||
|
||||
@@ -322,7 +323,8 @@ namespace XericUI.XTable.Rendering.Component
|
||||
if (m_Assembler == null)
|
||||
{
|
||||
if (rectTransform != null)
|
||||
m_Assembler = new CellAssembler(ContentTransform, m_DefaultStyleNamespace);
|
||||
m_Assembler = new CellAssembler(ContentTransform, m_DefaultStyleNamespace,
|
||||
Config.TextPoolMaxCapacity, Config.ImagePoolMaxCapacity);
|
||||
else return;
|
||||
}
|
||||
|
||||
|
||||
@@ -217,6 +217,14 @@ namespace XericUI.XTable.Rendering.Component
|
||||
|
||||
/// <summary>单元格内容水平内边距(单侧)</summary>
|
||||
private float CellPadding => Config.CellHorizontalPadding;
|
||||
|
||||
private void CreatePools()
|
||||
{
|
||||
m_Assembler = new CellAssembler(ContentTransform, m_DefaultStyleNamespace,
|
||||
Config.TextPoolMaxCapacity, Config.ImagePoolMaxCapacity);
|
||||
m_PrefabPool = new PrefabPrototypePool(ContentTransform, Config.PrefabPoolMaxCapacity);
|
||||
}
|
||||
|
||||
/// <summary>单元格内容宽度扣除量</summary>
|
||||
private float CellPadding2 => Config.CellHorizontalPadding * 2f;
|
||||
|
||||
@@ -281,8 +289,7 @@ namespace XericUI.XTable.Rendering.Component
|
||||
}
|
||||
}
|
||||
|
||||
m_Assembler = new CellAssembler(ContentTransform, m_DefaultStyleNamespace);
|
||||
m_PrefabPool = new PrefabPrototypePool(ContentTransform);
|
||||
CreatePools();
|
||||
m_ActivePrefabMap = new Dictionary<(int, int), GameObject>();
|
||||
UpdateResolvedCellSizes();
|
||||
RecalculateTotalSize();
|
||||
|
||||
@@ -49,13 +49,14 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
|
||||
#region 构造函数与析构
|
||||
|
||||
public CellAssembler(Transform parent, string defaultStyleNamespace = null)
|
||||
public CellAssembler(Transform parent, string defaultStyleNamespace = null, int textPoolMaxCapacity = 256,
|
||||
int imagePoolMaxCapacity = 256)
|
||||
{
|
||||
m_Parent = parent;
|
||||
m_DefaultStyleNamespace = defaultStyleNamespace;
|
||||
m_ImagePool = new SlotCounterPool<PooledImage>(() => CreateImage("cell_img"),
|
||||
m_ImagePool = new SlotCounterPool<PooledImage>(() => CreateImage("cell_img"), imagePoolMaxCapacity,
|
||||
SetImageCounterActive, SetImageCounterInactive);
|
||||
m_TextPool = new SlotCounterPool<PooledText>(() => CreateText("cell_text"),
|
||||
m_TextPool = new SlotCounterPool<PooledText>(() => CreateText("cell_text"), textPoolMaxCapacity,
|
||||
SetTextCounterActive, SetTextCounterInactive);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,13 +15,17 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
|
||||
private readonly Dictionary<GameObject, PrefabPool> m_Pools = new();
|
||||
private readonly Transform m_Parent;
|
||||
private const int MAX_PREFAB_ITEMS = 256;
|
||||
private readonly int m_MaxCapacity;
|
||||
private int m_TotalCreated;
|
||||
private const HideFlags POOL_FLAGS = HideFlags.DontSave | HideFlags.HideInHierarchy;
|
||||
private static readonly Vector2 AnchorTopLeft = new(0, 1);
|
||||
private static readonly Vector2 PivotTopLeft = new(0, 1);
|
||||
|
||||
public PrefabPrototypePool(Transform parent) => m_Parent = parent;
|
||||
public PrefabPrototypePool(Transform parent, int maxCapacity = 256)
|
||||
{
|
||||
m_Parent = parent;
|
||||
m_MaxCapacity = Mathf.Max(1, maxCapacity);
|
||||
}
|
||||
|
||||
public GameObject Acquire(GameObject prefab, int cellId, Transform parent = null)
|
||||
{
|
||||
@@ -100,9 +104,9 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
|
||||
private GameObject Create(GameObject prefab, Transform parent)
|
||||
{
|
||||
if (m_TotalCreated >= MAX_PREFAB_ITEMS)
|
||||
if (m_TotalCreated >= m_MaxCapacity)
|
||||
{
|
||||
Debug.LogWarning($"[XericUIActionTable] Prefab 池已达上限 {MAX_PREFAB_ITEMS},无法分配新实例");
|
||||
Debug.LogWarning($"[XericUIActionTable] Prefab 池已达上限 {m_MaxCapacity},无法分配新实例");
|
||||
return null;
|
||||
}
|
||||
GameObject instance = UnityEngine.Object.Instantiate(prefab, parent);
|
||||
|
||||
@@ -30,10 +30,11 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
|
||||
#region 字段
|
||||
|
||||
/// <summary>计数器数组大小(= 池上限,也是 cellId 路由键的模数)</summary>
|
||||
public const int POOL_SIZE = 256;
|
||||
/// <summary>cellId 路由桶数量。</summary>
|
||||
private const int ROUTE_BUCKET_COUNT = 256;
|
||||
|
||||
private readonly SlotCounter[] m_Counters = new SlotCounter[POOL_SIZE];
|
||||
private readonly SlotCounter[] m_Counters = new SlotCounter[ROUTE_BUCKET_COUNT];
|
||||
private readonly int m_MaxCreatedCount;
|
||||
private readonly Stack<SlotCounter> m_StandbyCounters = new Stack<SlotCounter>();
|
||||
private readonly Func<T> m_Factory;
|
||||
private readonly Action<IReadOnlyList<T>> m_OnCounterBorrowed;
|
||||
@@ -47,10 +48,11 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
|
||||
#region 构造
|
||||
|
||||
public SlotCounterPool(Func<T> factory, Action<IReadOnlyList<T>> onCounterBorrowed = null,
|
||||
Action<IReadOnlyList<T>> onCounterReturned = null)
|
||||
public SlotCounterPool(Func<T> factory, int maxCreatedCount = 256,
|
||||
Action<IReadOnlyList<T>> onCounterBorrowed = null, Action<IReadOnlyList<T>> onCounterReturned = null)
|
||||
{
|
||||
m_Factory = factory ?? throw new ArgumentNullException(nameof(factory));
|
||||
m_MaxCreatedCount = Mathf.Max(1, maxCreatedCount);
|
||||
m_OnCounterBorrowed = onCounterBorrowed;
|
||||
m_OnCounterReturned = onCounterReturned;
|
||||
}
|
||||
@@ -94,14 +96,14 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
|
||||
if (availableSlot == null)
|
||||
{
|
||||
if (m_CreatedCount >= POOL_SIZE)
|
||||
if (m_CreatedCount >= m_MaxCreatedCount)
|
||||
{
|
||||
if (borrowedCounter)
|
||||
{
|
||||
m_Counters[index] = null;
|
||||
m_StandbyCounters.Push(counter);
|
||||
}
|
||||
Debug.LogWarning($"[SlotCounterPool<{typeof(T).Name}>] 已达上限 {POOL_SIZE},无法分配新对象");
|
||||
Debug.LogWarning($"[SlotCounterPool<{typeof(T).Name}>] 已达上限 {m_MaxCreatedCount},无法分配新对象");
|
||||
isNewBinding = false;
|
||||
return null;
|
||||
}
|
||||
@@ -157,7 +159,7 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
{
|
||||
if (pooledObject == null) return false;
|
||||
|
||||
for (int ci = 0; ci < POOL_SIZE; ci++)
|
||||
for (int ci = 0; ci < ROUTE_BUCKET_COUNT; ci++)
|
||||
{
|
||||
var counter = m_Counters[ci];
|
||||
if (counter == null) continue;
|
||||
@@ -174,7 +176,7 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
/// <summary>解除全部槽位绑定,并将所有计数器整体归还待命栈。</summary>
|
||||
public void ReleaseAllBindings()
|
||||
{
|
||||
for (int ci = 0; ci < POOL_SIZE; ci++)
|
||||
for (int ci = 0; ci < ROUTE_BUCKET_COUNT; ci++)
|
||||
{
|
||||
var counter = m_Counters[ci];
|
||||
if (counter == null) continue;
|
||||
@@ -190,7 +192,7 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
{
|
||||
if (beforeRelease != null)
|
||||
{
|
||||
for (int ci = 0; ci < POOL_SIZE; ci++)
|
||||
for (int ci = 0; ci < ROUTE_BUCKET_COUNT; ci++)
|
||||
{
|
||||
var counter = m_Counters[ci];
|
||||
if (counter == null) continue;
|
||||
@@ -206,7 +208,7 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
{
|
||||
if (destroyFunc == null) return;
|
||||
var destroyedCounters = new HashSet<SlotCounter>();
|
||||
for (int ci = 0; ci < POOL_SIZE; ci++)
|
||||
for (int ci = 0; ci < ROUTE_BUCKET_COUNT; ci++)
|
||||
{
|
||||
var counter = m_Counters[ci];
|
||||
if (counter != null) destroyedCounters.Add(counter);
|
||||
@@ -221,8 +223,8 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
|
||||
private static int GetRouteIndex(int cellId)
|
||||
{
|
||||
int index = cellId % POOL_SIZE;
|
||||
return index < 0 ? index + POOL_SIZE : index;
|
||||
int index = cellId % ROUTE_BUCKET_COUNT;
|
||||
return index < 0 ? index + ROUTE_BUCKET_COUNT : index;
|
||||
}
|
||||
|
||||
private void ReturnCounter(int index, SlotCounter counter)
|
||||
|
||||
Reference in New Issue
Block a user