[Unity编辑器扩展基础总结] 第6章 EditorGUI、EdirotGUILayout介绍
第6章 EditorGUI、EdirotGUILayout介绍
6.1 EditorGUI、EditorGUILayout简介
EditorGUI/EditorGUILayout是编辑器扩展中各种控件的基类,它在运行时与GUI类具有相同的功能,区别是它也可以在非运行时执行,且只能在编辑器状态下使用, 具有编辑器的其他功能。
其中EditorGUILayout可以自动参与排版,所以用得比较多。
下面 ,我们使用EditorGUILayout在EditorWindow上显示一个字符。
using UnityEditor; using UnityEngine; public class EditorTest : EditorWindow { [MenuItem("Tools/Example")] static void Open() { GetWindow<EditorTest>(); } void OnGUI() { EditorGUILayout.LabelField("Example Label"); } }
6.2 变更检查 - EditorGUI.BeginChangeCheck
对在BeginChangeCheck和EndChangeCheck范围内的GUI进行任何更改时,EndChangeCheck将返回true。
using UnityEditor; using UnityEngine; public class EditorTest : EditorWindow { private bool toggleValue; [MenuItem("Tools/Example")] static void Open() { GetWindow<EditorTest>(); } void OnGUI() { EditorGUI.BeginChangeCheck(); toggleValue = EditorGUILayout.ToggleLeft("Toggle", toggleValue); if (EditorGUI.EndChangeCheck()) { Debug.Log("toggleValue值发生变化" + toggleValue.ToString()); } } }
GUI.changed
ChangeCheck也是使用GUI.changed来实现的,如果想用GUI.changed实现与ChangeCheck相同的功能,则可以用以下方式。
using System.Collections.Generic; using UnityEditor; using UnityEngine; public class EditorTest : EditorWindow { private bool toggleValue; private Stack<bool> stack = new Stack<bool>(); [MenuItem("Tools/Example")] static void Open() { GetWindow<EditorTest>(); } void OnGUI() { //EditorGUI.BeginChangeCheck(); stack.Push(GUI.changed); GUI.changed = false; toggleValue = EditorGUILayout.ToggleLeft("Toggle", toggleValue); bool changed = GUI.changed; GUI.changed |= stack.Pop(); if (changed) { Debug.Log("toggleValue值发生变化" + toggleValue.ToString()); } } }
6.3 禁用部分组件 - EditorGUI.BeginDisabledGroup(true)
using System.Collections.Generic; using UnityEditor; using UnityEngine; public class EditorTest : EditorWindow { private bool toggleValue; private Stack<bool> stack = new Stack<bool>(); [MenuItem("Tools/Example")] static void Open() { GetWindow<EditorTest>(); } void OnGUI() { Display(); EditorGUILayout.Space(); EditorGUI.BeginDisabledGroup(true); Display(); EditorGUI.EndDisabledGroup(); } void Display() { EditorGUILayout.ToggleLeft("Toggle", false); EditorGUILayout.IntSlider(0, 10, 0); GUILayout.Button("Button"); } }
GUI.enabled
GUI.enabled可以实现与
DisabledGroup相似的功能。如下
using System.Collections.Generic; using UnityEditor; using UnityEngine; public class EditorTest : EditorWindow { private bool toggleValue; [MenuItem("Tools/Example")] static void Open() { GetWindow<EditorTest>(); } void OnGUI() { Display(); EditorGUILayout.Space(); GUI.enabled = false; Display(); GUI.enabled = true; } void Display() { EditorGUILayout.ToggleLeft("Toggle", false); EditorGUILayout.IntSlider(0, 10, 0); GUILayout.Button("Button"); } }
6.4 淡出淡出一组GUI组件 - EditorGUILayout.BeginFadeGroup EditorGUILayout.EndFadeGroup()
用于淡入和淡出一组GUI,在淡入淡出期间我们是无法操作GUI的。下面我们通过按钮来触发淡入和淡出GUI。
using UnityEditor; using UnityEditor.AnimatedValues; using UnityEngine; using UnityEngine.Events; public class EditorTest : EditorWindow { private Texture m_tex; private AnimFloat m_animFloat = new AnimFloat(0.0001f); [MenuItem("Tools/Example")] static void Open() { GetWindow<EditorTest>(); } void OnGUI() { bool on = m_animFloat.value == 1; if (GUILayout.Button(on ? "Close" : "Open", GUILayout.Width(64))) { m_animFloat.target = on ? 0.0001f : 1; m_animFloat.speed = 0.1f; var env = new UnityEvent(); env.AddListener(() => Repaint()); m_animFloat.valueChanged = env; } EditorGUILayout.BeginHorizontal(); EditorGUILayout.BeginFadeGroup(m_animFloat.value); Display(); EditorGUILayout.EndFadeGroup(); Display(); EditorGUILayout.EndHorizontal(); } void Display() { EditorGUILayout.BeginVertical(); EditorGUILayout.ToggleLeft("Toggle", false); var options = new[] { GUILayout.Width(128), GUILayout.Height(128) }; m_tex = EditorGUILayout.ObjectField(m_tex, typeof(Texture), false, options) as Texture; GUILayout.Button("Button"); EditorGUILayout.EndVertical(); } }
6.5 对象引用的字段 - EditorGUILayout.ObjectField
处理对象引用的字段。可以在参数中指定要接受的对象类型。同样,纹理(Texture2D和Sprite)是特殊的缩略图字段。
void OnGUI() { EditorGUILayout.ObjectField(null, typeof(Object), false); EditorGUILayout.ObjectField(null, typeof(Material), false); EditorGUILayout.ObjectField(null, typeof(AudioClip), false); var options = new[] { GUILayout.Width(64), GUILayout.Height(64)}; EditorGUILayout.ObjectField(null, typeof(Texture), false, options); EditorGUILayout.ObjectField(null, typeof(Sprite), false, options); }
6.6 处理多浮点字段 - EditorGUI.MultiFloatField
它可以用于绘制在一行中编辑多个浮点值的字段,看起来就像在检查器中编辑Vector3的值。
using UnityEditor; using UnityEngine; public class EditorTest : EditorWindow { float[] numbers = new float[] { 0, 1, 2 }; GUIContent[] contents = new GUIContent[] { new GUIContent ("X"), new GUIContent ("Y"), new GUIContent ("Z")}; [MenuItem("Tools/Example")] static void Open() { GetWindow<EditorTest>(); } void OnGUI() { EditorGUI.MultiFloatField( new Rect(30, 30, 200, EditorGUIUtility.singleLineHeight), new GUIContent("位置点"), contents, numbers); } }
6.7 缩进级别 - EditorGUI.indentLevel
管理缩进级别。通过部分增加或减少缩进,可以实现检查器中那种层次结构。
可以适用于EditorGUI和EditorGUILayout。
using UnityEditor; using UnityEngine; public class EditorTest : EditorWindow { [MenuItem("Tools/Example")] static void Open() { GetWindow<EditorTest>(); } void OnGUI() { EditorGUILayout.LabelField("Parent"); EditorGUI.indentLevel++; EditorGUILayout.LabelField("Child"); EditorGUILayout.LabelField("Child"); EditorGUI.indentLevel--; EditorGUILayout.LabelField("Parent"); EditorGUI.indentLevel++; EditorGUILayout.LabelField("Child"); } }
6.8 EditorGUILayout.Knob
创建一个可以在指定范围内的变化的“旋钮”。可以通过使用鼠标拖动或单击显示的标签来直接输入值。
using UnityEditor; using UnityEngine; public class EditorTest : EditorWindow { private float angle = 0; [MenuItem("Tools/Example")] static void Open() { GetWindow<EditorTest>(); } void OnGUI() { angle = EditorGUILayout.Knob(Vector2.one * 64, angle, 0, 360, "度", Color.gray, Color.red, true); } }
6.9 范围 - HorizontalScope VerticalScope ScrollViewScope
用于管理 BeginHorizontal/EndHorizontal 排布的Helper类。在该范围内呈现的所有控件都将依次水平/垂直放置。使用Using语句就可以不需要BeginHorizontal和EndHorizontal。
void OnGUI() { // Starts a horizontal group using (var horizontalScope = new GUILayout.HorizontalScope("box")) { GUILayout.Button("Button1"); GUILayout.Button("Button2"); } // Now the group is ended. }
利用GUI.Scope自定义功能范围 背景色范围 - BackgroundColorScope
与HorizontalScope一样,背景色范围也是通过继承GUI.Scope类来创建的。
// 摘要:Disposable helper class for managing BeginHorizontal / EndHorizontal. public class HorizontalScope : GUI.Scope { public HorizontalScope(params GUILayoutOption[] options)
{
EditorGUILayout.BeginHorizontal();
} public HorizontalScope(GUIStyle style, params GUILayoutOption[] options); public HorizontalScope(string text, GUIStyle style, params GUILayoutOption[] options); public HorizontalScope(Texture image, GUIStyle style, params GUILayoutOption[] options); public HorizontalScope(GUIContent content, GUIStyle style, params GUILayoutOption[] options); protected override void CloseScope()
{
EditorGUILayout.EndHorizontal();
} }
CloseScope方法是在Dispose期间调用的。我们在构造函数中调用Begin,在CloseScope方法中调用End。
同样,可以使用继承GUI.Scope的类创建作用域。下面,我们创建一个BackgroundColorScope,仅在范围内更改GUI的背景。
using UnityEngine; public class BackgroundColorScope : GUI.Scope { private readonly Color color; public BackgroundColorScope(Color color) { this.color = GUI.backgroundColor; GUI.backgroundColor = color; } protected override void CloseScope() { GUI.backgroundColor = color; } }
GUI.backgroundColor在传递颜色信息之前,需要将其缓存起来,然后使用CloseScope将其恢复为原始颜色。
void OnGUI() { using (new BackgroundColorScope(Color.green)) { GUILayout.Button("Button"); using (new BackgroundColorScope(Color.yellow)) { GUILayout.Button("Button"); } } }
6.10 切换按钮外观
Unity Editor GUI具有许多按钮,这些按钮虽然看起来像按钮,但是具有开/关功能。
切换单个按钮样式 - GUILayout.Toggle
多个按钮时切换样式 - GUILayout.Toolbar
当我们想从多个选项中选择一个时
private bool one, two, three; void OnGUI() { using (new EditorGUILayout.HorizontalScope()) { one = GUILayout.Toggle(one, "1", EditorStyles.miniButtonLeft); two = GUILayout.Toggle(two, "2", EditorStyles.miniButtonMid); three = GUILayout.Toggle(three, "3", EditorStyles.miniButtonRight); } }
如果按钮很多的时候,我们需要定义很多的bool变量,管理起来就会非常麻烦,这时候我们可以使用GUILayout.Toolbar
轻松解决。
private int selected; private string[] btnAttr = new string[] { "1", "2", "3", "4", "5", "6" }; void OnGUI() { using (new EditorGUILayout.HorizontalScope()) { selected = GUILayout.Toolbar(selected, btnAttr); } }
当前的选项由int变量管理,显示的按钮由字符串数组管理。另外,通过更改GUIStyle,可以显示不同的按钮样式。
使用
EditorStyles.toolbarButton
来实现工具栏和切换器样式,例如在PlayerSettings平台设置中的工具栏和切换器。
void OnGUI() { using (new EditorGUILayout.HorizontalScope()) { selected = GUILayout.Toolbar(selected, btnAttr, EditorStyles.toolbarButton); } }
GUILayout.SelectionGrid
如果使用GUILayout.SelectionGrid将样式设置为PreferencesKeysElement(Unity内置的GUIStyle),那么所有选项将显示在一列中,这类似Preferences窗口中表示的选择菜单。
void OnGUI() { using (new EditorGUILayout.HorizontalScope()) { selected = GUILayout.SelectionGrid(selected, btnAttr, 1, "PreferencesKeysElement"); } }