第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"); } }