当前位置:   article > 正文

「Unity3D」(10)自定义属性面板Inspector详解_unity propertyfield

unity propertyfield

https://zhuanlan.zhihu.com/p/34234315

EditorGUILayout.PropertyField

Leave feedback

public static bool PropertyField(SerializedProperty property, params GUILayoutOption[] options);

public static bool PropertyField(SerializedProperty property, GUIContent label, params GUILayoutOption[] options);

public static bool PropertyField(SerializedProperty property, bool includeChildren, params GUILayoutOption[] options);

public static bool PropertyField(SerializedProperty property, GUIContent label, bool includeChildren, params GUILayoutOption[] options);

  1. //The scripts below show how to use a propertyField to change your editor.
  2. //Attach this first script to the GameObject that you would like to control. Add code in this script for any of the actions you require.
  3. using UnityEngine;
  4. public class MyGameObjectScript : MonoBehaviour
  5. {
  6. public int m_MyInt = 75;
  7. public Vector3 m_MyVector = new Vector3(20, 1, 0);
  8. public GameObject m_MyGameObject;
  9. }
  1. //This next script shows how to call upon variables from the "MyGameObject" Script (the first script) to make custom fields in the Inspector for these variables.
  2. using UnityEngine;
  3. using UnityEditor;
  4. // Custom Editor using SerializedProperties.
  5. // Automatic handling of multi-object editing, undo, and prefab overrides.
  6. [CustomEditor(typeof(MyGameObjectScript))]
  7. [CanEditMultipleObjects]
  8. public class EditorGUILayoutPropertyField : Editor
  9. {
  10. SerializedProperty m_IntProp;
  11. SerializedProperty m_VectorProp;
  12. SerializedProperty m_GameObjectProp;
  13. void OnEnable()
  14. {
  15. // Fetch the objects from the GameObject script to display in the inspector
  16. m_IntProp = serializedObject.FindProperty("m_MyInt");
  17. m_VectorProp = serializedObject.FindProperty("m_MyVector");
  18. m_GameObjectProp = serializedObject.FindProperty("m_MyGameObject");
  19. }
  20. public override void OnInspectorGUI()
  21. {
  22. //The variables and GameObject from the MyGameObject script are displayed in the Inspector with appropriate labels
  23. EditorGUILayout.PropertyField(m_IntProp, new GUIContent("Int Field"), GUILayout.Height(20));
  24. EditorGUILayout.PropertyField(m_VectorProp, new GUIContent("Vector Object"));
  25. EditorGUILayout.PropertyField(m_GameObjectProp, new GUIContent("Game Object"));
  26. // Apply changes to the serializedProperty - always do this at the end of OnInspectorGUI.
  27. serializedObject.ApplyModifiedProperties();
  28. }
  29. }

 

 

通常情况是不需要扩展属性面板的,也就是Inspector,但如果需要开发定制的工具和插件,那么就需要扩展属性面板来完成需求。本文会对自定义扩展Inspector进行全面的介绍。

工具类和概念的介绍

自定义Inspector有两个层面,第一个是扩展已有属性的功能,第二个是按照意图增加新的面板功能。扩展已有的功能,包括替换显示文字,动态控制可见性,增加动画,错误提示,数据的校验和限制等等。增加新的功能就是按照需求定制更为复杂的功能。

Unity的内置工具类提供了必要的实现基础,主要有EditorGUILayout和EditorGUI两大类。两者有重叠的部分,也有特有的部分。总体上来说,EditorGUILayout是带有自动布局的,EditorGUI需要传入Rect来对控件进行定位。另外,这两者和GUILayout与GUI概念非常类似,只不过GUI的主要绘制是在场景中(运行时,游戏中可见),EditorGUI上在Inspector中(仅在编辑器中)。

自定义流程

一共分为三步:

  • 第一步,继承Editor父类。
  • 第二步,添加[CustomEditor(typeof(MonoBehaviour))]注解,告诉编辑器这个类是扩展哪个组件的Inspector。
  • 第三步,覆写OnInspectorGUI方法,实现自定义的扩展。
  1. public class CustomEditorTest : MonoBehaviour
  2. {
  3. [Space(10)]
  4. public int intValue;
  5. public bool boolValue;
  6. public Vector2 v2;
  7. public float[] floatArray = new float[] {1.0f, 2.0f, 3.0f};
  8. }
  9. [CanEditMultipleObjects, CustomEditor(typeof(CustomEditorTest))]
  10. public class CustomEditorTestEditor : Editor
  11. {
  12. public override void OnInspectorGUI()
  13. {
  14. // 自定义绘制Inspector
  15. }
  16. }

自定义属性详细介绍

  • 绘制原有属性
  1. public override void OnInspectorGUI()
  2. {
  3. // 绘制全部原有属性
  4. base.DrawDefaultInspector()
  5. // 后面可以扩展自己功能
  6. }
  • 自定义绘制

有两个重要的内置对象,target和serializedObject。target代表的是CustomEditorTest本身,而serializedObject代表的是当前Inspector的可绘制对象。

  1. public override void OnInspectorGUI()
  2. {
  3. // 更新显示
  4. this.serializedObject.Update();
  5. // 自定义绘制
  6. // 应用属性修改
  7. this.serializedObject.ApplyModifiedProperties();
  8. }
  • 绘制已经有的属性

有两个接口用来查找已有的属性,FindProperty和FindPropertyRelative。FindProperty用来查找当前属性名对应的属性对象,FindPropertyRelative查找相对于属性对象的属性。

  1. // 显示intValue属性
  2. EditorGUILayout.PropertyField(this.serializedObject.FindProperty("intValue"));
  3. // 显示boolValue并替换属性标签为GUIContent
  4. EditorGUILayout.PropertyField(this.serializedObject.FindProperty("boolValue"), this.boolValueContent);
  5. var v2Property = this.serializedObject.FindProperty("v2");
  6. // 现实v2属性
  7. EditorGUILayout.PropertyField(v2Property);
  8. // 设置v2属性的x属性值
  9. v2Property.FindPropertyRelative("x").floatValue = 999.0f;
  10. // 分隔符
  11. EditorGUILayout.Separator();

EditorGUILayout.PropertyField能够在Inspector上绘制属性控件,如果返回false表示属性控件不可用,或者处在不可见的状态。

  • 绘制数组属性
  1. // 查找floatArray属性
  2. var elements = this.serializedObject.FindProperty("floatArray");
  3. // 属性元素可见,控件展开状态
  4. if (EditorGUILayout.PropertyField(elements))
  5. {
  6. // 缩进一级
  7. EditorGUI.indentLevel++;
  8. // 设置元素个数
  9. elements.arraySize = EditorGUILayout.DelayedIntField("Size", elements.arraySize);
  10. // 绘制元素
  11. for (int i = 0, size = elements.arraySize; i < size; i++)
  12. {
  13. // 检索属性数组元素
  14. var element = elements.GetArrayElementAtIndex(i);
  15. EditorGUILayout.PropertyField(element);
  16. }
  17. // 重置缩进
  18. EditorGUI.indentLevel--;
  19. }
  20. // 空格
  21. EditorGUILayout.Space();

对elements.arraySize赋值就会自动设置数组容量。DelayedIntField在回车的时候,控件设置的数值才会返回到arraySize。

  • 绘制默认数组和对象
  1. public CustomData data;
  2. public CustomData[] datas;
  3. [System.Serializable]
  4. public class CustomData
  5. {
  6. public int a;
  7. public int b;
  8. public int c;
  9. }
  10. // 第二个参数为true,则会默认绘制所有子元素
  11. EditorGUILayout.PropertyField(this.serializedObject.FindProperty("data"), true);
  12. EditorGUILayout.PropertyField(this.serializedObject.FindProperty("datas"), true);

  • 绘制折叠动画
  1. // 每个动画都需要一个AnimBool
  2. private AnimBool fadeGroup;
  3. private void OnEnable()
  4. {
  5. this.fadeGroup = new AnimBool(true);
  6. // 注册动画监听
  7. this.fadeGroup.valueChanged.AddListener(this.Repaint);
  8. }
  9. private void OnDisable()
  10. {
  11. // 移除动画监听
  12. this.fadeGroup.valueChanged.RemoveListener(this.Repaint);
  13. }
  14. // target控制动画开始播放
  15. this.fadeGroup.target = EditorGUILayout.Foldout(this.fadeGroup.target, "BeginFadeGroup", true);
  16. // 系统使用tween渐变faded数值
  17. if (EditorGUILayout.BeginFadeGroup(this.fadeGroup.faded))
  18. {
  19. EditorGUILayout.BoundsField("BoundsField", new Bounds());
  20. EditorGUILayout.BoundsIntField("BoundsIntField", new BoundsInt());
  21. }
  22. // begin - end 之间元素会进行动画
  23. EditorGUILayout.EndFadeGroup();
  24. // 又一种风格的空格
  25. GUILayout.Space(10);

Editor中依然可以使用GUILayout的功能。

  • 绘制水平布局
  1. // 水平布局,并使用box皮肤
  2. EditorGUILayout.BeginHorizontal(GUI.skin.box);
  3. // 使用了GUILayout去覆盖自动布局的设置
  4. EditorGUILayout.LabelField("This is BeginHorizontal",
  5. GUILayout.MaxWidth(150.0f));
  6. EditorGUILayout.DelayedDoubleField(11.1f);
  7. EditorGUILayout.DelayedTextField("DelayedTextField");
  8. EditorGUILayout.DropdownButton(GUIContent.none, FocusType.Passive);
  9. EditorGUILayout.EndHorizontal();
  10. EditorGUILayout.Separator();

  • 绘制垂直布局
  1. EditorGUILayout.BeginVertical(GUI.skin.box);
  2. // 依然可以使用GUILayout来显示控件
  3. GUILayout.Box("This is BeginVertical");
  4. EditorGUILayout.ColorField("ColorField", Color.yellow);
  5. EditorGUILayout.CurveField("CurveField", new AnimationCurve(),
  6. GUILayout.MaxWidth(400.0f));
  7. EditorGUILayout.HelpBox("HelpBox", MessageType.Info);
  8. EditorGUILayout.EnumFlagsField("EnumFlagsField", this.types);
  9. EditorGUILayout.EnumPopup("EnumPopup", this.types);
  10. this.selectOption = EditorGUILayout.IntPopup("IntPopup", (int) this.selectOption, new string[] {"0", "1", "2"}, new int[] {0, 1, 2});
  11. this.selectOption = EditorGUILayout.IntSlider("IntSlider", (int) this.selectOption, 0, 2);
  12. this.selectOption = EditorGUILayout.MaskField("MaskField", (int) this.selectOption, new string[] {"mask1", "mask2", "mask3"});
  13. this.selectOption = EditorGUILayout.Popup("Popup", (int) this.selectOption, new string[] {"s1", "s2", "s3"});
  14. EditorGUILayout.EndVertical();
  15. EditorGUILayout.Separator();

  • 绘制滚动区域
  1. // 超出内容会出现滚动条
  2. this.scrollPos = EditorGUILayout.BeginScrollView(this.scrollPos, GUI.skin.box);
  3. GUILayout.Box("this is BeginScrollView");
  4. EditorGUILayout.TextArea("this is TextArea");
  5. EditorGUILayout.RectField("RectField", new Rect());
  6. this.toggle = EditorGUILayout.Toggle("Toggle", this.toggle);
  7. // 在toggleGroup之间的会被整体设置可用性
  8. this.toggleGroup = EditorGUILayout.BeginToggleGroup("BeginToggleGroup", this.toggleGroup);
  9. GUILayout.Button("Btn1");
  10. GUILayout.Button("Btn2");
  11. GUILayout.Button("Btn3");
  12. EditorGUILayout.EndToggleGroup();
  13. EditorGUILayout.EndScrollView();

总结

  • PropertyField方法是用来显示已有属性控件的,第二个参数为true则绘制所有子元素。
  • Delayed开头的Field方法,是延迟控件。回车确定后,数值才会返回。
  • 其它Field方法是用来绘制自定义控件的。
  • Begin - End 是区域绘制控件,在之间的绘制会被整体控制。
  • 可以混合使用GUI和GUILayout以及EditorGUI进行绘制。
  • GUIContent 提供了重写控件名字和添加提示的机会。
  • GUILayoutOption 是覆盖自动布局的设置,属性来自于GUILayout类。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/80336
推荐阅读
相关标签
  

闽ICP备14008679号