//Add a header above some fields in the Inspector.
[Header("Tittle")]
public string Str;
//Specify a tooltip for a field.
[Tooltip("This is a Tooltip")]
public string Str;
//Attribute used to make a float or int variable in a script be restricted to a
//specific range.
[Range(0, 5)]
public int Int;
[Range(0, 5)]
public float Float;
//Attribute used to make a string value be shown in a multiline textarea.
[Multiline]
public string Str;
//Attribute to make a string be edited with a height-flexible and scrollable
//text area.
[TextArea(2, 5)]
public string Str;
//Adds the function to the context menu of the component.
[ContextMenu("QwQ")]
void HelloWorld()
{
Debug.Log("我发出了QwQ");
}
//Use this attribute to add a context menu to a field that calls a named method.
[ContextMenuItem("ResetValue", "resetValue")]
public int A = 100;
void resetValue()
{
A = 50;
}
//Makes a variable not show up in the inspector but be serialized.
[HideInInspector]
public string Str;
[Serializable]
public class SerializableTest
{
public int A = 5;
public Color c = Color.white;
}
public SerializableTest Test;
//Use this DecoratorDrawer to add some spacing in the Inspector.
public string Str0;
[Space(50)]
public string Str1;
[Serializable]
public class TestClass
{
public string Str = "这是一句话...";
public bool IsOn;
}
public class Test : MonoBehaviour
{
public TestClass testClass;
}
(1)在顶部菜单栏添加事件
public class Test : MonoBehaviour
{
[MenuItem("QAQ/QvQ")]
public static void QvQ()
{
print("O-O");
}
}
(2)在Project空白部分右键菜单栏添加事件
public class Test
{
const string menuA = "Assets/QAQ/QvQ";
const string menuB = "Assets/QAQ/Q_Q";
const string menuC = "Assets/QAQ/QuQ";
static bool isOn;
[MenuItem(menuA, priority = 0, validate = false)]
private static bool OvO()
{
bool value = !EditorPrefs.GetBool("HAHA", false);
EditorPrefs.SetBool("HAHA", value);
Menu.SetChecked(menuA, value);
isOn = value;
Debug.Log("OvO" + value);
return value;
}
[MenuItem(menuB, priority = 100)]
private static void O_O()
{
if (isOn)
Debug.Log("O_O");
}
[MenuItem(menuC)]
private static void OuO()
{
if (!isOn)
Debug.Log("OuO");
}
}
TestEditor类继承自Editor,[CustomEditor(typeof(Test))]特性指向Test类,可重写Test类的Inspector界面显示。
public class Test : MonoBehaviour
{
public string Str;
}
//Defines which object type the custom editor class can edit.
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
public override void OnInspectorGUI()
{
//基于原本Test类的所有原本布局
base.OnInspectorGUI();
}
}
在不基于原InspectorGUI的情况下,显示原Class中的变量。
(1)PropertyField
public class Test : MonoBehaviour
{
public string Str = "字符串";
}
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
SerializedProperty str;
private void OnEnable()
{
str = serializedObject.FindProperty("Str");
}
public override void OnInspectorGUI()
{
//base.OnInspectorGUI();
EditorGUILayout.PropertyField(str);
//str.stringValue = "string...";
//Apply property modifications.
serializedObject.ApplyModifiedProperties();
}
}
(2)Test t = (Test)target;
public class Test : MonoBehaviour
{
public string Str = "字符串";
}
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
public override void OnInspectorGUI()
{
Test t = (Test)target;
//以下写法一致
//Test t = target as Test;
t.Str = EditorGUILayout.TextField("_Str", t.Str);
}
}
(3)示例1
public class Test : MonoBehaviour
{
public bool IsOn = false;
public string Str = "QAQ";
public string Str1 = "T_T";
}
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
SerializedProperty str;
SerializedProperty str1;
private void OnEnable()
{
str = serializedObject.FindProperty("Str");
str1 = serializedObject.FindProperty("Str1");
}
public override void OnInspectorGUI()
{
Test t = (Test)target;
t.IsOn = EditorGUILayout.Toggle("_Toggle", t.IsOn);
if (t.IsOn)
{
EditorGUILayout.PropertyField(str);
}
else
{
EditorGUILayout.PropertyField(str1);
}
serializedObject.ApplyModifiedProperties();
}
}
(4)示例2
public class Test : MonoBehaviour
{
[Range(0,10)]
public int Int;
public enum TestType { A, B, C, }
public TestType _TestType;
//以下写法显示一样
//[SerializeField]
//TestType _TestType;
}
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
SerializedProperty _int;
SerializedProperty _testType;
private void OnEnable()
{
_int = serializedObject.FindProperty("Int");
_testType = serializedObject.FindProperty("_TestType");
}
public override void OnInspectorGUI()
{
EditorGUILayout.PropertyField(_testType);
EditorGUILayout.PropertyField(_int);
switch (_int.intValue)
{
case 1:
_testType.intValue = (int)TestNew.ETestType.Type1;
break;
case 2:
_testType.intValue = (int)TestNew.ETestType.Type2;
break;
default:
_testType.intValue = (int)TestNew.ETestType.Type3;
break;
}
serializedObject.ApplyModifiedProperties();
}
}
public class Test : MonoBehaviour
{
public string Str = "字符串";
public string Password = "123456";
public int Int = 1;
public float Float = 1.1f;
public double Double = 1.1;
public long Long = 1;
public bool Bool = true;
public Gradient Gradient = new Gradient();
public Color Color = Color.white;
public AnimationCurve Curve = AnimationCurve.Linear(0, 0, 10, 10);
public Vector2 V2 = new Vector2(1.1f, 1.1f);
public Vector2Int V2Int = new Vector2Int(1, 1);
public Vector3 V3 = new Vector3(1.1f, 1.1f, 1.1f);
public Vector3Int V3Int = new Vector3Int(1, 1, 1);
public Vector4 V4 = new Vector4(1.1f, 1.1f, 1.1f, 1.1f);
public Rect Rect = new Rect(1.1f, 1.1f, 1.1f, 1.1f);
public RectInt RectInt = new RectInt(1, 1, 1, 1);
public Bounds Bounds = new Bounds(new Vector3(1.1f, 1.1f, 1.1f), new Vector3(1.1f, 1.1f, 1.1f));
public BoundsInt BoundsInt = new BoundsInt(1, 1, 1, 1, 1, 1);
public GameObject GameObj;
public Camera Camera;
public Toggle Toggle;
}
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
public override void OnInspectorGUI()
{
Test t = (Test)target;
t.Str = EditorGUILayout.TextField("_Str", t.Str);//string
t.Password = EditorGUILayout.PasswordField("_Password", t.Password);//密码
t.Int = EditorGUILayout.IntField("_Int", t.Int);//int
t.Float = EditorGUILayout.FloatField("_Float", t.Float);//float
t.Double = EditorGUILayout.DoubleField("_Double", t.Double);//double
t.Long = EditorGUILayout.LongField("_Long", t.Long);//long
t.Bool = EditorGUILayout.Toggle("_Toggle", t.Bool);//bool值,以toggle方式显示
t.Gradient = EditorGUILayout.GradientField("_Gradient", t.Gradient);//颜色梯度
t.Color = EditorGUILayout.ColorField("_Color", t.Color);//color
t.Curve = EditorGUILayout.CurveField("_Curve", t.Curve);//curve曲线
t.V2 = EditorGUILayout.Vector2Field("_V2", t.V2);//Vector2
t.V2Int = EditorGUILayout.Vector2IntField("_V2Int", t.V2Int);//Vector2Int
t.V3 = EditorGUILayout.Vector3Field("_V3", t.V3);//Vector3
t.V4 = EditorGUILayout.Vector4Field("_V4", t.V4);//Vector4(X、Y、Z、W)
t.Rect = EditorGUILayout.RectField("_Rect", t.Rect);//Rect(X、Y、W、H)
t.RectInt = EditorGUILayout.RectIntField("_RectInt", t.RectInt);//RectInt(X、Y、W、H)
t.Bounds = EditorGUILayout.BoundsField("_Bounds", t.Bounds);//Bounds,两个三维变量
t.BoundsInt = EditorGUILayout.BoundsIntField("_BoundsInt", t.BoundsInt);//BoundsInt,两个三维整数变量
GUILayout.Space(20f);//20f的空白
GUILayout.Label("获取变量");
t.GameObj = (GameObject)EditorGUILayout.ObjectField("_GameObj", t.GameObj, typeof(GameObject), true);
t.Camera = (Camera)EditorGUILayout.ObjectField("_Camera", t.Camera, typeof(Camera), true);
t.Toggle = (Toggle)EditorGUILayout.ObjectField("_Toggle", t.Toggle, typeof(Toggle), true);
}
}
public class Test : MonoBehaviour
{
public string SelectableLabel = "我可以被复制";
public string Label = "哈哈哈";
public string StrDelayedField = "int,按Enter键或将焦点从字段移开之前,不会返回新值";
public float Slider = 1.1f;
public int SliderInt = 1;
public float SliderMin = 1.1f;
public float SliderMax = 2.2f;
public int PopupInt = 11;
public int PopupStrIndex = 0;
public int ArrayValue = 0;
public string[] StrArray = new string[] { "AA", "BB", "CC", "DD", "EE" };
public int[] IntArray = new int[] { 1, 2, 3, 4, 5 };
public enum EnumType { A, B, C, D }
public EnumType Enum0;
public EnumType Enum1;
public string Tag = "None";
public int Layer = 0;
}
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
public override void OnInspectorGUI()
{
Test t = (Test)target;
EditorGUILayout.SelectableLabel(t.SelectableLabel);//可复制文字
EditorGUILayout.LabelField("_Label", t.Label);//标签
GUILayout.Space(10f);
t.StrDelayedField = EditorGUILayout.DelayedTextField("_InputFieldEnter", t.StrDelayedField);
EditorGUILayout.HelpBox("与EditorGUILayout.TextField类似,但在按Enter键或将焦点从字段移开之前,不会返回新值。", MessageType.Info);
GUILayout.Space(10f);
t.Slider = EditorGUILayout.Slider("_Slider", t.Slider, 0, 10);//滑动条
t.SliderInt = EditorGUILayout.IntSlider("_IntSlider", t.SliderInt, 0, 10);//整数滑动条
EditorGUILayout.MinMaxSlider("_MinMaxSlider", ref t.SliderMin, ref t.SliderMax, 1, 10);// 最小值、最大值滑动条(现在最小值、现在最大值、最小值、最大值)
//下拉Int数选择框
t.PopupInt = EditorGUILayout.IntPopup("_IntPopup", t.PopupInt, new[] { "a", "b" }, new[] { 11, 22 });
//下拉string选择框
t.PopupStrIndex = EditorGUILayout.Popup("_PopupStr", t.PopupStrIndex, new[] { "AA", "BB", "CC", "DD", "EE" });
GUILayout.Space(10f);
t.ArrayValue = EditorGUILayout.MaskField("_MaskField:", t.ArrayValue, t.StrArray);//下拉选择框,可多选
EditorGUILayout.HelpBox("ArrayValue返回值为2的index次幂(0,-1,1,2,4,8,16...)(0、-1为nothing和everything选项),若多选则为各返回值的和", MessageType.Info);
GUILayout.Space(10f);
//下拉选择框
t.Enum0 = (Test.EnumType)EditorGUILayout.EnumFlagsField("_EnumType多选", t.Enum0);
t.Enum1 = (Test.EnumType)EditorGUILayout.EnumPopup("_EnumType单选", t.Enum1);
t.Tag = EditorGUILayout.TagField("_Tag", t.Tag);//Tag下拉框,可获取所有Tag
t.Layer = EditorGUILayout.LayerField("_Layer", t.Layer);//Layer下拉框,可获取所有Layer
}
}
public class Test : MonoBehaviour
{
}
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
bool isShowA;
bool isShowB;
float fspace = 0;
Vector2 scrollPos;
string scrollStr = "这是Scroll view区域";
public override void OnInspectorGUI()
{
Test t = (Test)target;
isShowA = EditorGUILayout.BeginToggleGroup("开启区域(BeginToggleGroup)", isShowA);
GUILayout.Label("这是一片区域A");
GUILayout.Label("----------------");
EditorGUILayout.EndToggleGroup();
EditorGUILayout.Space(20f);
GUILayout.Label("不同平台(BeginBuildTargetSelectionGrouping)");
BuildTargetGroup selectedBuildTargetGroup = EditorGUILayout.BeginBuildTargetSelectionGrouping();
if (selectedBuildTargetGroup == BuildTargetGroup.Android)
{
GUILayout.Label("安卓(BuildTargetGroup.Android)");
}
if (selectedBuildTargetGroup == BuildTargetGroup.WebGL)
{
GUILayout.Label("WebGL(BuildTargetGroup.WebGL)");
}
if (selectedBuildTargetGroup == BuildTargetGroup.Standalone)
{
GUILayout.Label("PC(BuildTargetGroup.Standalone)");
}
EditorGUILayout.EndBuildTargetSelectionGrouping();
EditorGUILayout.Space(10f);
GUILayout.Label("一个可变区域(BeginFadeGroup)");
fspace = EditorGUILayout.Slider("可变范围", fspace, 0f, 2);
if (EditorGUILayout.BeginFadeGroup(fspace))
{
GUILayout.Label("这是一片区域B");
}
EditorGUILayout.EndFadeGroup();
if (isShowB = EditorGUILayout.BeginFoldoutHeaderGroup(isShowB, "一个可展开的区域(BeginFoldoutHeaderGroup)"))
{
GUILayout.Label("这是一片区域C");
}
EditorGUILayout.EndFoldoutHeaderGroup();
GUILayout.Space(10f);
GUILayout.Label("一个Scroll区域(BeginScrollView)");
scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.Width(150), GUILayout.Height(100));
GUILayout.Label(scrollStr);
EditorGUILayout.EndScrollView();
//开始横向布局
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("添加一行文字", GUILayout.Width(100), GUILayout.Height(50)))
{
scrollStr += " \n添加一行文字-------------";
}
//开始纵向布局
EditorGUILayout.BeginVertical();
if (GUILayout.Button("Clear"))
{
scrollStr = "";
}
if (GUILayout.Button("诗经"))
{
scrollStr = "《蒹葭》\n 蒹葭苍苍,白露为霜。\n所谓伊人,在水一方。";
}
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
}
}
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
bool isShowA;
bool isShowB;
bool isShowC;
public override void OnInspectorGUI()
{
if (isShowA = EditorGUILayout.BeginFoldoutHeaderGroup(isShowA, "折叠(点击范围为一整行)"))
{
GUILayout.Box(new GUIContent("一个200x50的BOX"), new[] { GUILayout.Height(50), GUILayout.Width(200) });
}
EditorGUILayout.EndFoldoutHeaderGroup();
isShowB = EditorGUILayout.Foldout(isShowB, "折叠(只可点小三角)");
if (isShowB)
{
GUILayout.BeginHorizontal("Box", GUILayout.Width(500));
GUILayout.Label("水平布局", GUILayout.Width(100));
GUILayout.Button("Button", GUILayout.Width(200));
GUILayout.EndHorizontal();
}
isShowC = EditorGUILayout.InspectorTitlebar(isShowC, GameObject.Find("IsShowC"), true);
if (isShowC)
{
//用于解决EditorGUILayout和EditorGUI(或者GUI)混着用的情况
//这样确保自动布局不会乱, 不会叠在一起
Rect a = EditorGUILayout.GetControlRect();
EditorGUI.LabelField(a, "这是区域C");
EditorGUILayout.HelpBox("此处依据Hierarchy界面的GameObject物体的enabled状态来控制此处区域的开关", MessageType.Info);
GUILayout.Label("------------");
}
}
}
(1)HelpBox提示框
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.HelpBox("-------", MessageType.None);
EditorGUILayout.HelpBox("-------", MessageType.Info);
EditorGUILayout.HelpBox("-------", MessageType.Warning);
EditorGUILayout.HelpBox("-------", MessageType.Error);
}
}
(2)Event事件
public class Test : MonoBehaviour
{
[Serializable]
public class TestEvent1 : UnityEvent { }
[SerializeField]
private TestEvent1 Action1 = new TestEvent1();
public TestEvent1 testAction1
{
get { return Action1; }
set { Action1 = value; }
}
[Serializable]
public class TestEvent2 : UnityEvent { }
[SerializeField]
private TestEvent2 Action2 = new TestEvent2();
public TestEvent2 testAction2
{
get { return Action2; }
set { Action2 = value; }
}
}
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
SerializedProperty Action1;
SerializedProperty Action2;
private void OnEnable()
{
Action1 = serializedObject.FindProperty("Action1");
Action2 = serializedObject.FindProperty("Action2");
}
public override void OnInspectorGUI()
{
EditorGUILayout.PropertyField(Action1);
EditorGUILayout.PropertyField(Action2);
serializedObject.ApplyModifiedProperties();
}
}
(3)Button
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
GUIContent content;
private void OnEnable()
{
content = EditorGUIUtility.TrTextContent("测试按钮", "这是一个测试按钮", "PlayButton");
}
public override void OnInspectorGU()
{
if (GUILayout.Button(content))
{
Debug.Log("点击了测试按钮");
}
serializedObject.ApplyModifiedProperties();
//普通Button
if (GUILayout.Button("Button", GUILayout.Width(100), GUILayout.Height(30)))
{
//再次确认对话框DisplayDialog
if (EditorUtility.DisplayDialog("再次确定", "是否确定", "确定", "取消"))
{
Debug.Log("yes");
}
}
}
}
(3)Label,显示图片
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
public override void OnInspectorGUI()
{
GUILayout.Label("图片");
GUILayout.Label(Resources.Load("Icon"), GUILayout.Width(100), GUILayout.Height(100));
}
}
(5)LinkButton超链接
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.LinkButton("https://www.baidu.com");
}
}
(1)DisplayProgressBar
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
int range = 0;
public override void OnInspectorGUI()
{
range = EditorGUILayout.IntSlider("完成度", range, 0, 100);
if (range == 100 || range == 0)
{
EditorUtility.ClearProgressBar();
}
else
{
EditorUtility.DisplayProgressBar("进度条", "当前进度", range / 100f);
}
}
}
(2)Knob
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.Knob(new Vector2(50, 50), 40, 0, 100, "圆圈进度QvQ", Color.cyan, Color.blue, true);
EditorGUILayout.Knob(new Vector2(50, 50), 60, 0, 100, "圆圈进度QwQ", Color.yellow, Color.red, true);
}
}
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
int index = 0;
public override void OnInspectorGUI()
{
index = GUILayout.Toolbar(index, new[] { "A", "B", "C"});
switch (index)
{
case 0:
GUILayout.Label("这是A");
break;
case 1:
GUILayout.Label("这是B");
break;
case 2:
GUILayout.Label("这是C");
break;
}
}
无法打开文件,也无法保存文件,待研究。。。
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
string dir0, dir1, dir2, dir3, dir4, dir5;
public override void OnInspectorGUI()
{
if (GUILayout.Button("打开文件位置"))
{
dir0 = EditorUtility.OpenFilePanel("打开文件位置", dir0, ".txt");
}
if (GUILayout.Button("打开文件位置,筛选文件名称"))
{
dir1 = EditorUtility.OpenFilePanelWithFilters("打开文件位置", dir1, new[] { "haha", "txt" });
}
if (GUILayout.Button("选择文件路径"))
{
dir2 = EditorUtility.OpenFolderPanel("选择文件路径", dir2, "");
}
if (GUILayout.Button("保存文件"))
{
dir3 = EditorUtility.SaveFilePanel("保存文件", dir3, "name", ".txt");
}
if (GUILayout.Button("在项目内保存文件"))
{
dir4 = EditorUtility.SaveFilePanelInProject("在项目内保存文件", "name", "txt", "message");
}
if (GUILayout.Button("SaveFolderPanel"))
{
dir5 = EditorUtility.SaveFolderPanel("保存文件", dir5, "name");
}
GUILayout.Space(20f);
GUILayout.Label("-------------------------------------");
GUILayout.Label("无法打开文件,也无法保存文件,待研究");
}
}
[Serializable]
public class TestClass
{
public float x;
public float y;
public float z;
public float w;
}
public class Test : MonoBehaviour
{
public TestClass testClass;
}
[CustomPropertyDrawer(typeof(TestClass))]
public class TestClassEditor : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
Rect positionZ;
Rect positionW;
EditorGUI.BeginProperty(position, label, property);
//显示字段标签,返回标签占用后剩余的区域
if (position.width >= 200)
{
EditorGUIUtility.labelWidth = position.width / 3;
}
else
{
EditorGUIUtility.labelWidth = 50;
}
position = EditorGUI.PrefixLabel(position, label);
//区域宽度设置为一半
if (position.width >= 200)
{
position.width = position.width / 3;
}
else if (position.width < 100)
{
position.width = position.width / 2;
}
else
{
position.width = 70;
}
//调整标签Label宽度为当前的1/2
EditorGUIUtility.labelWidth = 15;
EditorGUI.PropertyField(position, property.FindPropertyRelative("x"));
positionZ = new Rect(position.x, position.y + 20, position.width, position.height);
EditorGUI.PropertyField(positionZ, property.FindPropertyRelative("z"));
//y属性右移
position.x += position.width + 5;
EditorGUI.PropertyField(position, property.FindPropertyRelative("y"));
positionW = new Rect(position.x, position.y + 20, position.width, position.height);
EditorGUI.PropertyField(positionW, property.FindPropertyRelative("w"));
EditorGUI.EndProperty();
}
}