修复表格的刷新工作流程,优化表格的操作,优化表格的序列化工作。
This commit is contained in:
@@ -8,7 +8,7 @@ namespace XericUIEditor.XTable
|
||||
{
|
||||
/// <summary>
|
||||
/// XericUIActionTable 的 Inspector 编辑器——
|
||||
/// 折叠分组:[样式设定] [尺寸设定] [编辑测试] [数据浏览]。
|
||||
/// 折叠分组:[样式设定] [尺寸设定] [调试] [数据浏览]。
|
||||
/// 使用 EditorGUILayout.Foldout 避免与数组 PropertyField 内部的折叠冲突。
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(XericUIActionTable))]
|
||||
@@ -24,23 +24,11 @@ namespace XericUIEditor.XTable
|
||||
// 折叠状态
|
||||
private static bool s_StyleFoldout = true;
|
||||
private static bool s_SizeFoldout = true;
|
||||
private static bool s_EditTestFoldout;
|
||||
private static bool s_DebugFoldout;
|
||||
private static bool s_DataBrowseFoldout;
|
||||
|
||||
// 编辑测试参数
|
||||
private int m_BatchRowCount = 10;
|
||||
private int m_BatchColCount = 10;
|
||||
private float m_BatchCellHeight = 40f;
|
||||
private float m_BatchCellWidth = 100f;
|
||||
|
||||
private int m_MergeStartRow;
|
||||
private int m_MergeStartCol;
|
||||
private int m_MergeRowSpan = 2;
|
||||
private int m_MergeColSpan = 2;
|
||||
|
||||
private int m_EditRow;
|
||||
private int m_EditCol;
|
||||
private string m_EditText = "";
|
||||
// 调试参数
|
||||
private bool m_ShowChildren;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
@@ -81,55 +69,35 @@ namespace XericUIEditor.XTable
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
// ===== 编辑测试 =====
|
||||
// ===== 调试 =====
|
||||
EditorGUILayout.Space(4);
|
||||
s_EditTestFoldout = EditorGUILayout.Foldout(s_EditTestFoldout, "编辑测试", true);
|
||||
if (s_EditTestFoldout)
|
||||
s_DebugFoldout = EditorGUILayout.Foldout(s_DebugFoldout, "调试", true);
|
||||
if (s_DebugFoldout)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
EditorGUILayout.LabelField("批量生成尺寸", EditorStyles.miniBoldLabel);
|
||||
m_BatchRowCount = EditorGUILayout.IntField("行数", m_BatchRowCount);
|
||||
m_BatchColCount = EditorGUILayout.IntField("列数", m_BatchColCount);
|
||||
m_BatchCellHeight = EditorGUILayout.FloatField("单元格高度", m_BatchCellHeight);
|
||||
m_BatchCellWidth = EditorGUILayout.FloatField("单元格宽度", m_BatchCellWidth);
|
||||
if (GUILayout.Button("应用批量尺寸", GUILayout.Height(22)))
|
||||
ApplyBatchRowColSizes();
|
||||
if (GUILayout.Button("重新生成表格", GUILayout.Height(26)))
|
||||
{
|
||||
m_Table.FullRebuild();
|
||||
m_Table.SetChildrenVisible(!m_ShowChildren);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(6);
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
EditorGUILayout.LabelField("合并单元格", EditorStyles.miniBoldLabel);
|
||||
m_MergeStartRow = EditorGUILayout.IntField("起始行", m_MergeStartRow);
|
||||
m_MergeStartCol = EditorGUILayout.IntField("起始列", m_MergeStartCol);
|
||||
m_MergeRowSpan = EditorGUILayout.IntField("行跨度", m_MergeRowSpan);
|
||||
m_MergeColSpan = EditorGUILayout.IntField("列跨度", m_MergeColSpan);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("合并", GUILayout.Height(22)))
|
||||
EditorApplication.delayCall += () => m_Table.MergeCells(m_MergeStartRow, m_MergeStartCol, m_MergeRowSpan, m_MergeColSpan);
|
||||
if (GUILayout.Button("取消合并", GUILayout.Height(22)))
|
||||
EditorApplication.delayCall += () => m_Table.UnmergeCells(m_MergeStartRow, m_MergeStartCol);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
bool newShow = EditorGUILayout.Toggle("显示子项", m_ShowChildren);
|
||||
if (newShow != m_ShowChildren)
|
||||
{
|
||||
m_ShowChildren = newShow;
|
||||
m_Table.SetChildrenVisible(m_ShowChildren);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(6);
|
||||
|
||||
EditorGUILayout.LabelField("单元格编辑", EditorStyles.miniBoldLabel);
|
||||
m_EditRow = EditorGUILayout.IntField("行", m_EditRow);
|
||||
m_EditCol = EditorGUILayout.IntField("列", m_EditCol);
|
||||
|
||||
var existing = m_Table.GetCellData(m_EditRow, m_EditCol);
|
||||
if (existing != null && !string.IsNullOrEmpty(existing.Text) && string.IsNullOrEmpty(m_EditText))
|
||||
m_EditText = existing.Text;
|
||||
|
||||
m_EditText = EditorGUILayout.TextField("文本内容", m_EditText);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("应用文本", GUILayout.Height(22)))
|
||||
EditorApplication.delayCall += () => m_Table.SetCellText(m_EditRow, m_EditCol, m_EditText);
|
||||
if (GUILayout.Button("选中此格", GUILayout.Height(22)))
|
||||
EditorApplication.delayCall += () => m_Table.SelectCell(m_EditRow, m_EditCol);
|
||||
if (GUILayout.Button("清除选中", GUILayout.Height(22)))
|
||||
EditorApplication.delayCall += () => m_Table.ClearSelection();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
if (m_ShowChildren)
|
||||
{
|
||||
EditorGUILayout.HelpBox(
|
||||
"子项已显示:所有动态生成的对象将在 Hierarchy 中可见(仍不保存到场景)。\n" +
|
||||
"用于排查表格元素堆积或渲染异常问题。",
|
||||
MessageType.Info);
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
@@ -166,27 +134,6 @@ namespace XericUIEditor.XTable
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private void ApplyBatchRowColSizes()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
if (m_RowHeightsProp != null)
|
||||
{
|
||||
m_RowHeightsProp.arraySize = m_BatchRowCount;
|
||||
for (int i = 0; i < m_BatchRowCount; i++)
|
||||
m_RowHeightsProp.GetArrayElementAtIndex(i).floatValue = m_BatchCellHeight;
|
||||
}
|
||||
|
||||
if (m_ColWidthsProp != null)
|
||||
{
|
||||
m_ColWidthsProp.arraySize = m_BatchColCount;
|
||||
for (int i = 0; i < m_BatchColCount; i++)
|
||||
m_ColWidthsProp.GetArrayElementAtIndex(i).floatValue = m_BatchCellWidth;
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
#region Hierarchy 创建菜单
|
||||
|
||||
[MenuItem("GameObject/Xeric UI/Table/Xeric UI Action Table", false, 60)]
|
||||
|
||||
@@ -2,6 +2,7 @@ using UnityEditor;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using XericLibrary.Runtime.SuperStyleSheet;
|
||||
using XericUI.XTable.Mapping;
|
||||
using XericUI.XTable.Rendering.Component;
|
||||
|
||||
@@ -137,10 +138,23 @@ namespace XericUIEditor.XTable
|
||||
// 底部内容输入框获得焦点:种子为当前单元格内容
|
||||
else if (newFocus == "XTableSceneEditInput" && s_ActiveTable != null)
|
||||
{
|
||||
int sr = s_ActiveTable.SelectedRow;
|
||||
int sc = s_ActiveTable.SelectedCol;
|
||||
if (sr >= 0 && sc >= 0)
|
||||
s_EditText = s_ActiveTable.GetCellData(sr, sc).Text ?? "";
|
||||
SyncEditText(s_ActiveTable);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>将 s_EditText 同步为当前选中单元格的内容(选中变更时调用)</summary>
|
||||
private static void SyncEditText(XericUIActionTable table)
|
||||
{
|
||||
int sr = table.SelectedRow;
|
||||
int sc = table.SelectedCol;
|
||||
if (sr >= 0 && sc >= 0)
|
||||
{
|
||||
var data = table.GetCellData(sr, sc);
|
||||
s_EditText = (data != null) ? (data.Text ?? "") : "";
|
||||
}
|
||||
else
|
||||
{
|
||||
s_EditText = "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,6 +352,7 @@ namespace XericUIEditor.XTable
|
||||
}
|
||||
|
||||
table.RefreshView();
|
||||
SyncEditText(table);
|
||||
Event.current.Use();
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
@@ -412,6 +427,7 @@ namespace XericUIEditor.XTable
|
||||
}
|
||||
|
||||
table.RefreshView();
|
||||
SyncEditText(table);
|
||||
Event.current.Use();
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
@@ -719,7 +735,12 @@ namespace XericUIEditor.XTable
|
||||
|
||||
private static void DrawInputBar(XericUIActionTable table, float x, float y)
|
||||
{
|
||||
Rect barRect = new Rect(x, y, 500, 24);
|
||||
const float barW = 450;
|
||||
const float barH = 52;
|
||||
const float rowH = 22;
|
||||
const float pad = 2;
|
||||
|
||||
Rect barRect = new Rect(x, y, barW, barH);
|
||||
EditorGUI.DrawRect(barRect, s_InputBg);
|
||||
|
||||
if (table.SelectedRow >= 0 && table.SelectedCol >= 0)
|
||||
@@ -730,17 +751,26 @@ namespace XericUIEditor.XTable
|
||||
normal = { textColor = s_LabelText },
|
||||
alignment = TextAnchor.MiddleCenter
|
||||
};
|
||||
|
||||
string cellLabel = table.GetSelectionText();
|
||||
GUI.Label(new Rect(barRect.x + 4, barRect.y, 75, barRect.height),
|
||||
cellLabel, labelStyle);
|
||||
|
||||
var inputStyle = new GUIStyle(GUI.skin.textField)
|
||||
{
|
||||
fontSize = 12,
|
||||
margin = new RectOffset(2, 2, 2, 2)
|
||||
margin = new RectOffset(1, 1, 1, 1)
|
||||
};
|
||||
Rect inputRect = new Rect(barRect.x + 85, barRect.y + 2, 200, barRect.height - 4);
|
||||
var btnStyle = new GUIStyle(GUI.skin.button)
|
||||
{
|
||||
fontSize = 11,
|
||||
margin = new RectOffset(1, 1, 1, 1),
|
||||
padding = new RectOffset(4, 4, 2, 2)
|
||||
};
|
||||
|
||||
// Row 1: 坐标标签 | 输入框 | 应用按钮
|
||||
float btnW = 44;
|
||||
float row1Y = barRect.y + pad;
|
||||
float row2Y = barRect.y + rowH + pad + 4;
|
||||
string cellLabel = table.GetSelectionText();
|
||||
|
||||
GUI.Label(new Rect(barRect.x + 4, row1Y, 60, rowH), cellLabel, labelStyle);
|
||||
Rect inputRect = new Rect(barRect.x + 68, row1Y, barW - 68 - btnW - pad * 2, rowH);
|
||||
|
||||
// 回车提交(仅在 CellEditing 状态下)
|
||||
if (s_State == EditorState.CellEditing &&
|
||||
@@ -754,18 +784,40 @@ namespace XericUIEditor.XTable
|
||||
GUI.SetNextControlName("XTableSceneEditInput");
|
||||
s_EditText = GUI.TextField(inputRect, s_EditText, inputStyle);
|
||||
|
||||
var btnStyle = new GUIStyle(GUI.skin.button)
|
||||
{
|
||||
fontSize = 11,
|
||||
margin = new RectOffset(2, 2, 2, 2),
|
||||
padding = new RectOffset(4, 4, 2, 2)
|
||||
};
|
||||
if (GUI.Button(new Rect(barRect.x + 370, barRect.y + 2, 50, barRect.height - 4),
|
||||
if (GUI.Button(new Rect(barRect.x + barW - btnW - pad, row1Y, btnW, rowH),
|
||||
"应用", btnStyle))
|
||||
{
|
||||
GUI.FocusControl(null);
|
||||
ApplyCellEdit(table);
|
||||
}
|
||||
|
||||
// Row 2: 样式命名空间下拉框
|
||||
var nsLabelStyle = new GUIStyle(GUI.skin.label)
|
||||
{
|
||||
fontSize = 10,
|
||||
normal = { textColor = new Color(0.6f, 0.6f, 0.6f) },
|
||||
alignment = TextAnchor.MiddleRight
|
||||
};
|
||||
GUI.Label(new Rect(barRect.x + 4, row2Y, 36, rowH), "样式:", nsLabelStyle);
|
||||
|
||||
// 获取当前命名空间
|
||||
string currentNS = table.GetCellStyleNamespace(
|
||||
table.SelectedRow, table.SelectedCol) ?? "";
|
||||
|
||||
// 构建下拉选项(StyleManager.GetAvailableNamespaces 已保证 "default" 在首位)
|
||||
var namespaces = StyleManager.GetAvailableNamespaces();
|
||||
int currentIdx = namespaces.IndexOf(currentNS);
|
||||
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);
|
||||
|
||||
if (newIdx != currentIdx && newIdx >= 0 && newIdx < namespaces.Count)
|
||||
{
|
||||
table.SetCellStyleNamespace(table.SelectedRow, table.SelectedCol,
|
||||
namespaces[newIdx]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -775,7 +827,8 @@ namespace XericUIEditor.XTable
|
||||
normal = { textColor = new Color(0.5f, 0.5f, 0.5f) },
|
||||
alignment = TextAnchor.MiddleCenter
|
||||
};
|
||||
GUI.Label(barRect, "点击左侧行号或上方列名选中单元格 | Shift+方向键多选", hintStyle);
|
||||
GUI.Label(new Rect(barRect.x, barRect.y, barW, barH / 2),
|
||||
"点击左侧行号或上方列名选中单元格 | Shift+方向键多选", hintStyle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -823,6 +876,7 @@ namespace XericUIEditor.XTable
|
||||
}
|
||||
|
||||
table.RefreshView();
|
||||
SyncEditText(table);
|
||||
e.Use();
|
||||
SceneView.RepaintAll();
|
||||
break;
|
||||
@@ -835,6 +889,7 @@ namespace XericUIEditor.XTable
|
||||
|
||||
table.ExtendMultiSelect(dragRow, dragCol);
|
||||
table.RefreshView();
|
||||
SyncEditText(table);
|
||||
e.Use();
|
||||
SceneView.RepaintAll();
|
||||
break;
|
||||
@@ -870,6 +925,7 @@ namespace XericUIEditor.XTable
|
||||
table.ClearSelection();
|
||||
table.RefreshView();
|
||||
s_EditText = "";
|
||||
SyncEditText(table);
|
||||
e.Use();
|
||||
SceneView.RepaintAll();
|
||||
return;
|
||||
@@ -899,6 +955,7 @@ namespace XericUIEditor.XTable
|
||||
|
||||
table.SelectCell(row, col);
|
||||
table.RefreshView();
|
||||
SyncEditText(table);
|
||||
e.Use();
|
||||
SceneView.RepaintAll();
|
||||
return;
|
||||
@@ -934,6 +991,7 @@ namespace XericUIEditor.XTable
|
||||
}
|
||||
|
||||
table.RefreshView();
|
||||
SyncEditText(table);
|
||||
e.Use();
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
|
||||
@@ -20,16 +20,23 @@ namespace XericUI.XTable.Core
|
||||
#region 属性
|
||||
|
||||
/// <summary>块内列数(默认 <see cref="DefaultBlockSize"/>)</summary>
|
||||
public int BlockSizeX { get; private set; }
|
||||
[field: SerializeField] public int BlockSizeX { get; private set; }
|
||||
|
||||
/// <summary>块内行数(默认 <see cref="DefaultBlockSize"/>)</summary>
|
||||
public int BlockSizeY { get; private set; }
|
||||
[field: SerializeField] public int BlockSizeY { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 块字典——key = Z 曲线索引(ulong),value = 数据块。
|
||||
/// 具有哈希表性质,按需创建,键不连续(离散存储)。
|
||||
/// 注意:Dictionary 不被 Unity 序列化器原生支持,通过 <see cref="m_BlockKeys"/> / <see cref="m_BlockValues"/> 代理序列化。
|
||||
/// </summary>
|
||||
public Dictionary<ulong, XTableBlock> BlockMap { get; private set; }
|
||||
[NonSerialized] public Dictionary<ulong, XTableBlock> BlockMap;
|
||||
|
||||
// ── Dictionary 序列化代理 ──
|
||||
// Unity 无法直接序列化 Dictionary<ulong, XTableBlock>,
|
||||
// 使用两个平行列表在 OnBeforeSerialize/OnAfterDeserialize 中转换。
|
||||
[SerializeField] private List<ulong> m_BlockKeys = new List<ulong>();
|
||||
[SerializeField] private List<XTableBlock> m_BlockValues = new List<XTableBlock>();
|
||||
|
||||
/// <summary>
|
||||
/// 获取或创建单元格——如果单元格不存在则自动创建空数据。
|
||||
@@ -74,13 +81,36 @@ namespace XericUI.XTable.Core
|
||||
|
||||
#region 序列化回调
|
||||
|
||||
public void OnBeforeSerialize() { }
|
||||
public void OnBeforeSerialize()
|
||||
{
|
||||
// Dictionary → 平行列表
|
||||
m_BlockKeys.Clear();
|
||||
m_BlockValues.Clear();
|
||||
if (BlockMap != null)
|
||||
{
|
||||
foreach (var kv in BlockMap)
|
||||
{
|
||||
m_BlockKeys.Add(kv.Key);
|
||||
m_BlockValues.Add(kv.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAfterDeserialize()
|
||||
{
|
||||
if (BlockSizeX <= 0) BlockSizeX = DefaultBlockSize;
|
||||
if (BlockSizeY <= 0) BlockSizeY = DefaultBlockSize;
|
||||
if (BlockMap == null) BlockMap = new Dictionary<ulong, XTableBlock>();
|
||||
|
||||
// 平行列表 → Dictionary
|
||||
BlockMap = new Dictionary<ulong, XTableBlock>();
|
||||
int count = System.Math.Min(
|
||||
m_BlockKeys?.Count ?? 0,
|
||||
m_BlockValues?.Count ?? 0);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (m_BlockValues[i] != null)
|
||||
BlockMap[m_BlockKeys[i]] = m_BlockValues[i];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace XericUI.XTable.Core
|
||||
{
|
||||
/// <summary>
|
||||
@@ -8,7 +10,7 @@ namespace XericUI.XTable.Core
|
||||
/// 同一类型支持本地块内引用和跨块引用,通过 <see cref="IsCrossBlock"/> 区分。
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class XTableMergeDescriptor
|
||||
public class XTableMergeDescriptor : ISerializationCallbackReceiver
|
||||
{
|
||||
/// <summary>合并区域在本地块内的起始行</summary>
|
||||
public int LocalStartRow;
|
||||
@@ -37,8 +39,12 @@ namespace XericUI.XTable.Core
|
||||
/// <summary>源单元格在块内的列号(跨块时=源块的列、本地时=本块的列)</summary>
|
||||
public int SourceLocalCol;
|
||||
|
||||
/// <summary>本块内被合并的 (row, col) 集合,查询时快速判断是否需要重定向</summary>
|
||||
public HashSet<(int row, int col)> MergedCellSet;
|
||||
/// <summary>本块内被合并的 (row, col) 集合——不参与序列化,通过代理列表同步</summary>
|
||||
[NonSerialized] public HashSet<(int row, int col)> MergedCellSet;
|
||||
|
||||
// ── HashSet 序列化代理 ──
|
||||
[SerializeField] private List<int> m_MergedRowList = new List<int>();
|
||||
[SerializeField] private List<int> m_MergedColList = new List<int>();
|
||||
|
||||
public XTableMergeDescriptor()
|
||||
{
|
||||
@@ -63,5 +69,37 @@ namespace XericUI.XTable.Core
|
||||
targetRow = SourceLocalRow;
|
||||
targetCol = SourceLocalCol;
|
||||
}
|
||||
|
||||
#region 序列化回调
|
||||
|
||||
public void OnBeforeSerialize()
|
||||
{
|
||||
// HashSet<(int,int)> → 两个平行列表
|
||||
m_MergedRowList.Clear();
|
||||
m_MergedColList.Clear();
|
||||
if (MergedCellSet != null)
|
||||
{
|
||||
foreach (var (row, col) in MergedCellSet)
|
||||
{
|
||||
m_MergedRowList.Add(row);
|
||||
m_MergedColList.Add(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAfterDeserialize()
|
||||
{
|
||||
// 两个平行列表 → HashSet<(int,int)>
|
||||
MergedCellSet = new HashSet<(int, int)>();
|
||||
int count = System.Math.Min(
|
||||
m_MergedRowList?.Count ?? 0,
|
||||
m_MergedColList?.Count ?? 0);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
MergedCellSet.Add((m_MergedRowList[i], m_MergedColList[i]));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -39,6 +39,9 @@ namespace XericUI.XTable.Rendering.Elements
|
||||
private Transform m_Parent;
|
||||
private Transform m_PoolRoot;
|
||||
|
||||
/// <summary>池根节点(所有回收对象均挂在此节点下,节点本身处于 inactive)</summary>
|
||||
public Transform PoolRoot => m_PoolRoot;
|
||||
|
||||
private Stack<PooledImage> m_ImagePool = new Stack<PooledImage>();
|
||||
private Stack<PooledText> m_TextPool = new Stack<PooledText>();
|
||||
private List<PooledImage> m_ActiveImages = new List<PooledImage>();
|
||||
|
||||
Reference in New Issue
Block a user