diff --git a/Editor/XTable/XericUIActionTableSceneEditor.cs b/Editor/XTable/XericUIActionTableSceneEditor.cs index 2283bdc..ad8e609 100644 --- a/Editor/XTable/XericUIActionTableSceneEditor.cs +++ b/Editor/XTable/XericUIActionTableSceneEditor.cs @@ -16,17 +16,31 @@ namespace XericUIEditor.XTable [InitializeOnLoad] public static class XericUIActionTableSceneEditor { + // ─────────────────────────── 交互状态机 ─────────────────────────── + private enum EditorState + { + TableNavigation, // 默认:键盘/鼠标在表格上导航与选择 + SizeEditing, // 气泡输入框中编辑行高/列宽 + CellEditing // 底部工具栏中编辑单元格文本内容 + } + + private static EditorState s_State; + private static string s_CurrentControlName; // 当前聚焦的控件名(每帧由焦点决定) + private static bool s_Enabled; private const string ENABLED_KEY = "XericUI_TableSceneEditor_Enabled"; private static string s_EditText = ""; + private static string s_SizeEditText = ""; // 气泡输入框当前编辑文本 + private static int s_SizeEditTargetIndex = -1; + private static bool s_SizeEditIsColumn; + private static string s_LastFocusedControl = ""; // 拖拽框选状态 private static bool s_IsDragging; - private static bool s_DragFromLabel; // 拖拽是否从行/列标签发起 private static int s_DragStartRow = -1; private static int s_DragStartCol = -1; - private static Rect s_TableRect; // 当前表格区域(用于拖拽期间鼠标检测) + private static Rect s_TableRect; private static float s_XScale, s_YScale; private static float[] s_RowHeights, s_ColWidths; private static XericUIActionTable s_ActiveTable; @@ -38,6 +52,11 @@ namespace XericUIEditor.XTable private static readonly Color s_InputBg = new Color(0.08f, 0.08f, 0.14f, 0.92f); private static readonly Color s_SelectionColor = new Color(0.18f, 0.45f, 0.85f, 0.25f); private static readonly Color s_MultiSelectRangeColor = new Color(0.18f, 0.45f, 0.85f, 0.12f); + private static readonly Color s_BubbleBg = new Color(0.08f, 0.1f, 0.2f, 0.95f); + private static readonly Color s_BubbleBorder = new Color(0.3f, 0.5f, 0.9f, 0.8f); + private static readonly Color s_ApplyBtnColor = new Color(0.15f, 0.4f, 0.15f, 0.9f); + private static readonly Color s_AddBtnBg = new Color(0.15f, 0.3f, 0.15f, 0.8f); + private static readonly Color s_AddBtnHover = new Color(0.2f, 0.45f, 0.2f, 0.9f); private const float ROW_H = 22f; private const float COL_W = 36f; @@ -65,6 +84,70 @@ namespace XericUIEditor.XTable return true; } + // ═══════════════════════════════════════════════════════════════ + // 状态机入口 + // ═══════════════════════════════════════════════════════════════ + + private static void UpdateState() + { + string focused = GUI.GetNameOfFocusedControl(); + + // 检测焦点切换 → 种子编辑文本 + if (focused != s_LastFocusedControl) + { + s_LastFocusedControl = focused; + OnFocusChanged(focused); + } + + if (string.IsNullOrEmpty(focused)) + s_State = EditorState.TableNavigation; + else if (focused.StartsWith("XTableColSizeEdit_") || focused.StartsWith("XTableRowSizeEdit_")) + s_State = EditorState.SizeEditing; + else if (focused == "XTableSceneEditInput") + s_State = EditorState.CellEditing; + else + s_State = EditorState.TableNavigation; + + s_CurrentControlName = focused; + } + + private static void OnFocusChanged(string newFocus) + { + // 气泡输入框获得焦点:种子为当前尺寸值 + if (newFocus.StartsWith("XTableColSizeEdit_") && s_ActiveTable != null) + { + if (int.TryParse(newFocus.Substring("XTableColSizeEdit_".Length), out int idx)) + { + s_SizeEditIsColumn = true; + s_SizeEditTargetIndex = idx; + s_SizeEditText = s_ColWidths != null && idx < s_ColWidths.Length + ? s_ColWidths[idx].ToString("F0") : ""; + } + } + else if (newFocus.StartsWith("XTableRowSizeEdit_") && s_ActiveTable != null) + { + if (int.TryParse(newFocus.Substring("XTableRowSizeEdit_".Length), out int idx)) + { + s_SizeEditIsColumn = false; + s_SizeEditTargetIndex = idx; + s_SizeEditText = s_RowHeights != null && idx < s_RowHeights.Length + ? s_RowHeights[idx].ToString("F0") : ""; + } + } + // 底部内容输入框获得焦点:种子为当前单元格内容 + 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 ?? ""; + } + } + + // ═══════════════════════════════════════════════════════════════ + // 主入口 + // ═══════════════════════════════════════════════════════════════ + private static void OnSceneGUI(SceneView sceneView) { if (!s_Enabled) return; @@ -106,15 +189,33 @@ namespace XericUIEditor.XTable Rect tableRect = new Rect(guiTL.x, guiTL.y, tableW, tableH); + // 更新缓存 + s_TableRect = tableRect; + s_XScale = xScale; + s_YScale = yScale; + s_RowHeights = rh; + s_ColWidths = cw; + s_ActiveTable = table; + Handles.BeginGUI(); + // ★ 状态机:必须最先执行,后续所有逻辑依赖 s_State + UpdateState(); + DrawRowLabels(rh, tableRect, xScale, yScale, table); DrawColumnLabels(cw, tableRect, xScale, yScale, table); DrawGridLines(rh, cw, tableRect, xScale, yScale); DrawSelectionHighlight(rh, cw, tableRect, xScale, yScale, table); + DrawAddButtons(rh, cw, tableRect, xScale, yScale, table); + DrawSizeEditBubble(rh, cw, tableRect, xScale, yScale, table); DrawInputBar(table, tableRect.x, tableRect.y + tableRect.height + MARGIN); - HandleInput(table, rh, cw, tableRect, xScale, yScale); - HandleKeyboard(table, rh, cw); + + // 非导航状态不处理鼠标/键盘表格操作 + if (s_State == EditorState.TableNavigation) + { + HandleTableMouse(table, rh, cw, tableRect, xScale, yScale); + HandleKeyboard(table, rh, cw); + } Handles.EndGUI(); } @@ -132,7 +233,20 @@ namespace XericUIEditor.XTable return -1; } - /// 判断某行是否在多选范围内 + private static float SumBefore(float[] arr, int count) + { + float sum = 0; + for (int i = 0; i < count && i < arr.Length; i++) sum += arr[i]; + return sum; + } + + private static float SumRange(float[] arr, int start, int end) + { + float sum = 0; + for (int i = start; i < end && i < arr.Length; i++) sum += arr[i]; + return sum; + } + private static bool IsRowInMultiSelect(XericUIActionTable table, int row) { if (!table.HasMultiSelection) return false; @@ -141,7 +255,6 @@ namespace XericUIEditor.XTable return row >= minR && row <= maxR; } - /// 判断某列是否在多选范围内 private static bool IsColInMultiSelect(XericUIActionTable table, int col) { if (!table.HasMultiSelection) return false; @@ -150,10 +263,16 @@ namespace XericUIEditor.XTable return col >= minC && col <= maxC; } - /// 更新 s_EditText 为当前焦点格的单元格内容 - private static void UpdateEditText(XericUIActionTable table, int row, int col) + /// 创建纯色 1x1 纹理,用于按钮背景 + private static Texture2D MakeTex(int w, int h, Color col) { - s_EditText = table.GetCellData(row, col).Text ?? ""; + Color[] pix = new Color[w * h]; + for (int i = 0; i < pix.Length; i++) + pix[i] = col; + Texture2D result = new Texture2D(w, h); + result.SetPixels(pix); + result.Apply(); + return result; } #endregion @@ -193,6 +312,9 @@ namespace XericUIEditor.XTable EditorGUI.DrawRect(labelRect, bgColor); GUI.Label(labelRect, $"{r}", style); + // 表格导航状态下才响应鼠标 + if (s_State != EditorState.TableNavigation) { y += cellH; continue; } + if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && labelRect.Contains(Event.current.mousePosition)) @@ -201,7 +323,6 @@ namespace XericUIEditor.XTable if (col < 0) col = 0; s_IsDragging = true; - s_DragFromLabel = true; s_DragStartRow = r; s_DragStartCol = col; @@ -217,7 +338,6 @@ namespace XericUIEditor.XTable } table.RefreshView(); - UpdateEditText(table, r, col); Event.current.Use(); SceneView.RepaintAll(); } @@ -266,6 +386,9 @@ namespace XericUIEditor.XTable string text = cellW > 40 ? colLetter : (cellW > 18 ? colLetter : ""); GUI.Label(labelRect, text, style); + // 表格导航状态下才响应鼠标 + if (s_State != EditorState.TableNavigation) { x += cellW; continue; } + if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && labelRect.Contains(Event.current.mousePosition)) @@ -274,7 +397,6 @@ namespace XericUIEditor.XTable if (row < 0) row = 0; s_IsDragging = true; - s_DragFromLabel = true; s_DragStartRow = row; s_DragStartCol = c; @@ -290,7 +412,6 @@ namespace XericUIEditor.XTable } table.RefreshView(); - UpdateEditText(table, row, c); Event.current.Use(); SceneView.RepaintAll(); } @@ -334,7 +455,6 @@ namespace XericUIEditor.XTable int sc = table.SelectedCol; if (sr < 0 || sc < 0 || sr >= rh.Length || sc >= cw.Length) return; - // 多选范围高亮 if (table.HasMultiSelection) { int minR = Mathf.Min(table.SelectStartRow, table.SelectEndRow); @@ -356,7 +476,6 @@ namespace XericUIEditor.XTable s_MultiSelectRangeColor); } - // 焦点格高亮(始终绘制) float sx = tr.x + SumBefore(cw, sc) * xScale; float sy = tr.y + SumBefore(rh, sr) * yScale; float sw = cw[sc] * xScale; @@ -366,18 +485,206 @@ namespace XericUIEditor.XTable s_SelectionColor); } - private static float SumBefore(float[] arr, int count) + #endregion + + #region 添加行列按钮 + + private static void DrawAddButtons(float[] rh, float[] cw, Rect tr, + float xScale, float yScale, XericUIActionTable table) { - float sum = 0; - for (int i = 0; i < count && i < arr.Length; i++) sum += arr[i]; - return sum; + var plusStyle = new GUIStyle(GUI.skin.label) + { + fontSize = 14, + fontStyle = FontStyle.Bold, + normal = { textColor = Color.white }, + alignment = TextAnchor.MiddleCenter + }; + + float yEnd = tr.y + tr.height; + Rect rowBtn = new Rect(tr.x - COL_W - MARGIN, yEnd + MARGIN, COL_W, ROW_H); + + bool rowHover = rowBtn.Contains(Event.current.mousePosition); + EditorGUI.DrawRect(rowBtn, rowHover ? s_AddBtnHover : s_AddBtnBg); + GUI.Label(rowBtn, "+", plusStyle); + + if (Event.current.type == EventType.MouseDown && + Event.current.button == 0 && rowHover) + { + table.AddRow(); + table.RefreshView(); + Event.current.Use(); + SceneView.RepaintAll(); + } + + float xEnd = tr.x + tr.width; + Rect colBtn = new Rect(xEnd + MARGIN, tr.y - ROW_H - MARGIN, COL_W, ROW_H); + + bool colHover = colBtn.Contains(Event.current.mousePosition); + EditorGUI.DrawRect(colBtn, colHover ? s_AddBtnHover : s_AddBtnBg); + GUI.Label(colBtn, "+", plusStyle); + + if (Event.current.type == EventType.MouseDown && + Event.current.button == 0 && colHover) + { + table.AddColumn(); + table.RefreshView(); + Event.current.Use(); + SceneView.RepaintAll(); + } } - private static float SumRange(float[] arr, int start, int end) + #endregion + + #region 气泡尺寸编辑器(含应用按钮) + + private const float BUBBLE_W = 60; + private const float BUBBLE_H = 22; + private const float BUBBLE_APPLY_BTN_W = 24; + + private static GUIStyle s_BubbleApplyBtnStyle; + + private static void EnsureBubbleStyles() { - float sum = 0; - for (int i = start; i < end && i < arr.Length; i++) sum += arr[i]; - return sum; + if (s_BubbleApplyBtnStyle != null) return; + s_BubbleApplyBtnStyle = new GUIStyle(GUI.skin.button) + { + fontSize = 11, + fontStyle = FontStyle.Bold, + normal = { textColor = Color.white, background = MakeTex(1, 1, s_ApplyBtnColor) }, + hover = { textColor = Color.white, background = MakeTex(1, 1, new Color(0.2f, 0.55f, 0.2f, 0.95f)) }, + active = { textColor = Color.white, background = MakeTex(1, 1, new Color(0.1f, 0.4f, 0.1f, 0.95f)) }, + padding = new RectOffset(0, 0, 0, 0), + margin = new RectOffset(0, 0, 0, 0), + alignment = TextAnchor.MiddleCenter, + border = new RectOffset(0, 0, 0, 0) + }; + } + + private static void DrawSizeEditBubble(float[] rh, float[] cw, Rect tr, + float xScale, float yScale, XericUIActionTable table) + { + int selRow = table.SelectedRow; + int selCol = table.SelectedCol; + + // 列宽气泡 + if (selCol >= 0 && selCol < cw.Length && selRow < 0) + { + float cx = tr.x + SumBefore(cw, selCol) * xScale; + float cwScaled = cw[selCol] * xScale; + float bubbleX = cx + cwScaled / 2f - BUBBLE_W / 2f; + float bubbleY = tr.y - ROW_H - MARGIN - 28f; + DrawBubble(table, bubbleX, bubbleY, cw[selCol], isColumn: true, index: selCol); + } + + if (selRow >= 0 && selRow < rh.Length && selCol < 0) + { + float ry = tr.y + SumBefore(rh, selRow) * yScale; + float rhScaled = rh[selRow] * yScale; + float bubbleX = tr.x - COL_W - MARGIN - 86f; + float bubbleY = ry + rhScaled / 2f - 12f; + DrawBubble(table, bubbleX, bubbleY, rh[selRow], isColumn: false, index: selRow); + } + + if (selRow >= 0 && selCol >= 0) + { + if (selCol < cw.Length) + { + float cx = tr.x + SumBefore(cw, selCol) * xScale; + float cwScaled = cw[selCol] * xScale; + float bubbleX = cx + cwScaled / 2f - BUBBLE_W / 2f; + float bubbleY = tr.y - ROW_H - MARGIN - 28f; + DrawBubble(table, bubbleX, bubbleY, cw[selCol], isColumn: true, index: selCol); + } + if (selRow < rh.Length) + { + float ry = tr.y + SumBefore(rh, selRow) * yScale; + float rhScaled = rh[selRow] * yScale; + float bubbleX = tr.x - COL_W - MARGIN - 86f; + float bubbleY = ry + rhScaled / 2f - 12f; + DrawBubble(table, bubbleX, bubbleY, rh[selRow], isColumn: false, index: selRow); + } + } + } + + private static void DrawBubble(XericUIActionTable table, + float x, float y, float currentValue, + bool isColumn, int index) + { + string controlName = isColumn + ? $"XTableColSizeEdit_{index}" + : $"XTableRowSizeEdit_{index}"; + bool isFocused = GUI.GetNameOfFocusedControl() == controlName; + + // 气泡容器(含输入框 + 应用按钮) + float totalW = isFocused ? BUBBLE_W + BUBBLE_APPLY_BTN_W + 2f : BUBBLE_W; + Rect bubbleRect = new Rect(x - (isFocused ? (BUBBLE_APPLY_BTN_W + 2f) / 2f : 0), y, totalW, BUBBLE_H); + + EditorGUI.DrawRect(bubbleRect, s_BubbleBg); + EditorGUI.DrawRect(new Rect(bubbleRect.x, bubbleRect.y, bubbleRect.width, 1), s_BubbleBorder); + EditorGUI.DrawRect(new Rect(bubbleRect.x, bubbleRect.y + BUBBLE_H - 1, bubbleRect.width, 1), s_BubbleBorder); + EditorGUI.DrawRect(new Rect(bubbleRect.x, bubbleRect.y, 1, BUBBLE_H), s_BubbleBorder); + EditorGUI.DrawRect(new Rect(bubbleRect.x + bubbleRect.width - 1, bubbleRect.y, 1, BUBBLE_H), s_BubbleBorder); + + var inputStyle = new GUIStyle(GUI.skin.textField) + { + fontSize = 11, + margin = new RectOffset(1, 1, 1, 1), + alignment = TextAnchor.MiddleCenter + }; + + Rect inputRect = new Rect(bubbleRect.x + 2, bubbleRect.y + 2, + BUBBLE_W - 4, BUBBLE_H - 4); + + GUI.SetNextControlName(controlName); + + if (isFocused) + { + s_SizeEditText = GUI.TextField(inputRect, s_SizeEditText, inputStyle); + } + else + { + GUI.TextField(inputRect, currentValue.ToString("F0"), inputStyle); + } + + // ── 应用按钮(GUI.Button 确保正确交互)── + if (isFocused) + { + EnsureBubbleStyles(); + Rect applyBtnRect = new Rect( + bubbleRect.x + BUBBLE_W + 2f, bubbleRect.y, + BUBBLE_APPLY_BTN_W, BUBBLE_H); + + if (GUI.Button(applyBtnRect, "✓", s_BubbleApplyBtnStyle)) + { + ApplyBubbleEdit(table, isColumn, index); + GUI.FocusControl(null); + } + } + + // 回车提交 + if (isFocused && + Event.current.type == EventType.KeyDown && + Event.current.keyCode == KeyCode.Return) + { + ApplyBubbleEdit(table, isColumn, index); + Event.current.Use(); + } + } + + private static void ApplyBubbleEdit(XericUIActionTable table, bool isColumn, int index) + { + string trimmed = s_SizeEditText.Trim(); + if (float.TryParse(trimmed, out float value) && value > 0) + { + if (isColumn) + table.SetColWidth(index, value); + else + table.SetRowHeight(index, value); + table.RefreshView(); + } + GUI.FocusControl(null); + s_State = EditorState.TableNavigation; + SceneView.RepaintAll(); } #endregion @@ -398,7 +705,6 @@ namespace XericUIEditor.XTable alignment = TextAnchor.MiddleCenter }; - // 单元格坐标(单选 "A0",多选 "A0:B1") string cellLabel = table.GetSelectionText(); GUI.Label(new Rect(barRect.x + 4, barRect.y, 75, barRect.height), cellLabel, labelStyle); @@ -410,11 +716,12 @@ namespace XericUIEditor.XTable }; Rect inputRect = new Rect(barRect.x + 85, barRect.y + 2, 200, barRect.height - 4); - // 回车键提交 - if (Event.current.isKey && Event.current.keyCode == KeyCode.Return - && GUI.GetNameOfFocusedControl() == "XTableSceneEditInput") + // 回车提交(仅在 CellEditing 状态下) + if (s_State == EditorState.CellEditing && + Event.current.type == EventType.KeyDown && + Event.current.keyCode == KeyCode.Return) { - ApplyEdit(table); + ApplyCellEdit(table); Event.current.Use(); } @@ -431,7 +738,7 @@ namespace XericUIEditor.XTable "应用", btnStyle)) { GUI.FocusControl(null); - ApplyEdit(table); + ApplyCellEdit(table); } } else @@ -446,32 +753,25 @@ namespace XericUIEditor.XTable } } - private static void ApplyEdit(XericUIActionTable table) + private static void ApplyCellEdit(XericUIActionTable table) { if (table.SelectedRow < 0 || table.SelectedCol < 0) return; table.SetCellText(table.SelectedRow, table.SelectedCol, s_EditText); table.RefreshView(); + s_State = EditorState.TableNavigation; SceneView.RepaintAll(); } #endregion - #region 表格区域点击与拖拽 + #region 表格区域鼠标(仅 TableNavigation 状态调用) - private static void HandleInput(XericUIActionTable table, + private static void HandleTableMouse(XericUIActionTable table, float[] rh, float[] cw, Rect tr, float xScale, float yScale) { Event e = Event.current; - // 更新当前帧的表格参数缓存,供拖拽期间使用 - s_TableRect = tr; - s_XScale = xScale; - s_YScale = yScale; - s_RowHeights = rh; - s_ColWidths = cw; - s_ActiveTable = table; - switch (e.type) { case EventType.MouseDown: @@ -482,7 +782,6 @@ namespace XericUIEditor.XTable if (mdRow < 0 || mdCol < 0) break; s_IsDragging = true; - s_DragFromLabel = false; s_DragStartRow = mdRow; s_DragStartCol = mdCol; @@ -498,7 +797,6 @@ namespace XericUIEditor.XTable } table.RefreshView(); - UpdateEditText(table, mdRow, mdCol); e.Use(); SceneView.RepaintAll(); break; @@ -511,7 +809,6 @@ namespace XericUIEditor.XTable table.ExtendMultiSelect(dragRow, dragCol); table.RefreshView(); - UpdateEditText(table, dragRow, dragCol); e.Use(); SceneView.RepaintAll(); break; @@ -532,28 +829,15 @@ namespace XericUIEditor.XTable row = IndexFromCoord(ry, s_RowHeights); } - /// 被行标签/列标签拖拽时调用,将拖拽扩展到整行/整列方向 - private static void StartDragFromLabel(int row, int col, XericUIActionTable table) - { - s_IsDragging = true; - s_DragStartRow = row; - s_DragStartCol = col; - table.StartMultiSelect(row, col); - } - #endregion - #region 键盘快捷键 + #region 键盘(仅 TableNavigation 状态调用) private static void HandleKeyboard(XericUIActionTable table, float[] rh, float[] cw) { Event e = Event.current; if (e.type != EventType.KeyDown) return; - // 输入框获得焦点时不拦截方向键(用于文本光标移动) - if (GUI.GetNameOfFocusedControl() == "XTableSceneEditInput") - return; - // Escape 清除选区 if (e.keyCode == KeyCode.Escape) { @@ -589,7 +873,6 @@ namespace XericUIEditor.XTable table.SelectCell(row, col); table.RefreshView(); - UpdateEditText(table, row, col); e.Use(); SceneView.RepaintAll(); return; @@ -624,7 +907,6 @@ namespace XericUIEditor.XTable table.SelectCell(row, col); } - UpdateEditText(table, row, col); table.RefreshView(); e.Use(); SceneView.RepaintAll(); diff --git a/Runtime/XTable/Rendering/Component/XericUIActionTable.cs b/Runtime/XTable/Rendering/Component/XericUIActionTable.cs index b938538..f9c8cc2 100644 --- a/Runtime/XTable/Rendering/Component/XericUIActionTable.cs +++ b/Runtime/XTable/Rendering/Component/XericUIActionTable.cs @@ -266,6 +266,70 @@ namespace XericUI.XTable.Rendering.Component MarkDirty(TableDirtyType.DataChanged); } + /// 在末尾追加一行,默认行高 40 + public void AddRow(float height = 40f) + { +#if UNITY_EDITOR + UnityEditor.Undo.RecordObject(this, "Add Table Row"); +#endif + int newLen = m_RowHeights.Length + 1; + var newArr = new float[newLen]; + System.Array.Copy(m_RowHeights, newArr, m_RowHeights.Length); + newArr[newLen - 1] = height; + m_RowHeights = newArr; + MarkDirty(TableDirtyType.LayoutChanged); +#if UNITY_EDITOR + UnityEditor.EditorUtility.SetDirty(this); +#endif + } + + /// 在末尾追加一列,默认列宽 100 + public void AddColumn(float width = 100f) + { +#if UNITY_EDITOR + UnityEditor.Undo.RecordObject(this, "Add Table Column"); +#endif + int newLen = m_ColWidths.Length + 1; + var newArr = new float[newLen]; + System.Array.Copy(m_ColWidths, newArr, m_ColWidths.Length); + newArr[newLen - 1] = width; + m_ColWidths = newArr; + MarkDirty(TableDirtyType.LayoutChanged); +#if UNITY_EDITOR + UnityEditor.EditorUtility.SetDirty(this); +#endif + } + + /// 设置指定行的高度 + public void SetRowHeight(int row, float height) + { + if (row < 0 || row >= m_RowHeights.Length) return; + if (height <= 0) return; +#if UNITY_EDITOR + UnityEditor.Undo.RecordObject(this, "Set Row Height"); +#endif + m_RowHeights[row] = height; + MarkDirty(TableDirtyType.LayoutChanged); +#if UNITY_EDITOR + if (!Application.isPlaying) UnityEditor.EditorUtility.SetDirty(this); +#endif + } + + /// 设置指定列的宽度 + public void SetColWidth(int col, float width) + { + if (col < 0 || col >= m_ColWidths.Length) return; + if (width <= 0) return; +#if UNITY_EDITOR + UnityEditor.Undo.RecordObject(this, "Set Column Width"); +#endif + m_ColWidths[col] = width; + MarkDirty(TableDirtyType.LayoutChanged); +#if UNITY_EDITOR + if (!Application.isPlaying) UnityEditor.EditorUtility.SetDirty(this); +#endif + } + public void SelectCell(int row, int col) { ClearMultiSelection(); @@ -356,10 +420,19 @@ namespace XericUI.XTable.Rendering.Component public void RefreshView() { - if (m_Assembler == null) return; + // 编辑模式下 Awake 可能尚未执行,按需回退初始化 + if (m_Assembler == null) + { + if (rectTransform != null) + m_Assembler = new CellAssembler(rectTransform); + else return; + } + if (m_RowHeights == null || m_ColWidths == null) return; if (m_RowHeights.Length == 0 || m_ColWidths.Length == 0) return; + CreateBackground(); + #if UNITY_EDITOR if (!Application.isPlaying) Canvas.ForceUpdateCanvases();