Unity EditorWindow中ObjectField标签与控件的大间距如何消除
Unity编辑器ObjectField标签与控件间大间距问题解决
问题表现
编写Unity编辑器窗口脚本时,为ObjectField控件添加前置字符串标签后,标签与对象选择控件间出现大幅空白间距,常规布局调整方案无法生效。
原始实现代码
using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; public class RenameSelected : EditorWindow { private static readonly Vector2Int size = new Vector2Int(500, 500); bool showPosition = false; GameObject[] objects; Vector2 scrollPos; [MenuItem("GameObject/Rename Selected")] public static void Init() { EditorWindow window = GetWindow<RenameSelected>(); window.minSize = size; window.maxSize = size; } private void OnSelectionChange() { objects = Selection.gameObjects; } private void OnEnable() { objects = Selection.gameObjects; } public void OnGUI() { if (objects.Length == 0) { showPosition = false; } GUILayout.Space(20); EditorGUI.BeginChangeCheck(); EditorGUILayout.GetControlRect(true, 16f, EditorStyles.foldout); Rect foldRect = GUILayoutUtility.GetLastRect(); if (Event.current.type == EventType.MouseUp && foldRect.Contains(Event.current.mousePosition)) { showPosition = !showPosition; GUI.changed = true; Event.current.Use(); } showPosition = EditorGUI.Foldout(foldRect, showPosition, "Objects"); GUILayout.Space(2); if (showPosition) { EditorGUI.indentLevel++; scrollPos = EditorGUILayout.BeginScrollView(scrollPos); for (int i = 0; i < objects.Length; i++) { objects[i] = (GameObject)EditorGUILayout.ObjectField(i.ToString() ,objects[i], typeof(GameObject), true); } EditorGUILayout.EndScrollView(); EditorGUI.indentLevel--; } Repaint(); } }
无效尝试代码
曾尝试通过水平布局+FlexibleSpace消除间距,未生效,代码如下:
EditorGUILayout.BeginHorizontal(); for (int i = 0; i < objects.Length; i++) { objects[i] = (GameObject)EditorGUILayout.ObjectField(i.ToString() ,objects[i], typeof(GameObject), true); GUILayout.FlexibleSpace(); } EditorGUILayout.EndHorizontal();
问题根因
- Unity IMGUI编辑器系统默认会为所有带前置标签的控件预留固定宽度的标签占位区,该宽度由全局参数
EditorGUIUtility.labelWidth控制,默认值约180像素。当前使用的数字序号标签仅占20像素左右,剩余的预留宽度就形成了大片空白。 - 缩进层级
EditorGUI.indentLevel会进一步叠加标签区域的预留宽度,放大空白问题。 - 之前的水平布局写法存在逻辑错误:将整个列表循环放在同一个水平布局块中,会导致所有ObjectField横向排列在同一行,既无法消除单控件内部的标签间距,还会造成控件重叠、布局错乱。
解决方案
方案1:修改全局标签宽度(适配性最好,代码改动最小)
在渲染列表前临时修改标签宽度为适配短标签的数值,渲染完成后还原默认值,避免影响其他编辑器控件的正常显示。核心修改代码如下:
if (showPosition) { EditorGUI.indentLevel++; // 备份默认标签宽度,设置适配数字序号的宽度 float originLabelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = 20f; // 可根据标签实际长度微调数值 scrollPos = EditorGUILayout.BeginScrollView(scrollPos); for (int i = 0; i < objects.Length; i++) { objects[i] = (GameObject)EditorGUILayout.ObjectField(i.ToString(), objects[i], typeof(GameObject), true); } EditorGUILayout.EndScrollView(); // 还原默认标签宽度 EditorGUIUtility.labelWidth = originLabelWidth; EditorGUI.indentLevel--; }
方案2:逐行自定义水平布局(自由度最高)
如果不想修改全局参数,可以为每一行列表项单独创建水平布局,手动拆分标签和控件,自定义宽度和间距:
if (showPosition) { EditorGUI.indentLevel++; scrollPos = EditorGUILayout.BeginScrollView(scrollPos); for (int i = 0; i < objects.Length; i++) { // 注意:每一行单独开启水平布局,不能把整个循环包在同一个水平块里 EditorGUILayout.BeginHorizontal(); // 绘制固定宽度的前置标签 GUILayout.Label(i.ToString(), GUILayout.Width(20f)); // ObjectField内置标签留空,占满剩余行宽 objects[i] = (GameObject)EditorGUILayout.ObjectField("", objects[i], typeof(GameObject), true); EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndScrollView(); EditorGUI.indentLevel--; }
提示:两种方案的宽度数值都可以根据实际标签长度调整,比如标签是3个汉字就把宽度设为40-50像素,达到最紧凑的显示效果。
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

