1. Inherit Editor and rewrite OnInspector GUI method
Effect
Realization
Define a test class TestClass, a serializable class DataClass
[CreateAssetMenu]
public class TestClass : ScriptableObject
{
[Range(0, 10)]
public int intData;
public string stringData;
public List<DataClass> dataList;
}
[System.Serializable]
public class DataClass
{
[Range(0, 100)]
public int id;
public Vector3 position;
public List<int> list;
}
//Specified type
[CustomEditor(typeof(TestClass))]
public class TestClassEditor : Editor
{
SerializedProperty intField;
SerializedProperty stringField;
void OnEnable()
{
//Gets the specified field
intField = serializedObject.FindProperty("intData");
stringField = serializedObject.FindProperty("stringData");
}
public override void OnInspectorGUI()
{
// Update the serializedProperty - always do this in the beginning of OnInspectorGUI.
serializedObject.Update();
EditorGUILayout.IntSlider(intField, 0, 100, new GUIContent("initData"));
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(stringField);
if(GUILayout.Button("Select"))
{
stringField.stringValue = EditorUtility.OpenFilePanel("", Application.dataPath, "");
}
EditorGUILayout.EndHorizontal();
// Apply changes to the serializedProperty - always do this in the end of OnInspectorGUI.
//You need to modify attributes before OnInspector GUI, otherwise you cannot modify values
serializedObject.ApplyModifiedProperties();
base.OnInspectorGUI();
}
}
Editor nesting
adopt Edtiro.CreateEditor Editor can be nested.
Create a class TestClass2 that contains the properties of a TestClass.
[CreateAssetMenu]
public class TestClass2 : ScriptableObject
{
public TestClass data;
}
Create an asset for Test2Class. The default display of its Inspector panel is:
It does not show the properties of TestClass. If you want to view the properties of TestClass, you must double-click and jump to the corresponding interface, but you can't see the properties of TestClass2.
If you want to see and modify the properties of TestClass directly in the Inspector panel of Test2Class, you can override the Editor of TestClass2 and nest the Editor of TestClass in it.
[CustomEditor(typeof(TestClass2))]
public class TestClass2Editor : Editor
{
Editor cacheEditor;
public override void OnInspectorGUI()
{
// Update the serializedProperty - always do this in the beginning of OnInspectorGUI.
serializedObject.Update();
//Display the default UI for TestClass2
base.OnInspectorGUI();
GUILayout.Space(20);
var data = ( (TestClass2)target ).data;
if(data != null)
{
//Editor for Creating TestClass
if (cacheEditor == null)
cacheEditor = Editor.CreateEditor(data);
GUILayout.Label("this is TestClass2");
cacheEditor.OnInspectorGUI();
}
}
}
This allows you to view and edit the properties of TestClass directly in the TestClass2 panel.
2. Use Property Drawer
Property Drawer official document
If you want to modify a particular type of display, using the inheritance of Editor can become very cumbersome, because all use of a specific type of asset need to implement a custom Editor, which is very inefficient. In this case, the attributes of the specified type can be uniformly displayed by inheriting Property Drawer.
Effect
Add a select File button for all string attributes in the Inspector panel, and assign the path of the selected file directly to the variable.
Realization
[CustomPropertyDrawer(typeof(string))]
public class StringPropertyDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
Rect btnRect = new Rect(position);
position.width -= 60;
btnRect.x += btnRect.width - 60;
btnRect.width = 60;
EditorGUI.BeginProperty(position, label, property);
EditorGUI.PropertyField(position, property, true);
if (GUI.Button(btnRect, "select"))
{
string path = property.stringValue;
string selectStr = EditorUtility.OpenFilePanel("Select Files", path, "");
if (!string.IsNullOrEmpty(selectStr))
{
property.stringValue = selectStr;
}
}
EditorGUI.EndProperty();
}
}
After adding a Property Drawer, all ** string variables in the Inspector panel add an additional Select button.
Matters needing attention
- Property Drawer is only valid for serializable classes, and non-serializable classes cannot be displayed in the Inspector panel.
- OnGUI method can only use GUI-related methods, not Layout-related methods.
- Property Drawer modifies the way all attributes of the corresponding type are displayed, such as creating a MonobeBehavior with string attributes:
3. Use Property Attribute
Property Attribute Official Document
If you want to modify the display of attributes of specified types of some classes, you can't meet the requirement by using Property Drawer directly. At this time, you can combine Property Attribute and Property Attribute to realize the requirement.
Effect
Add slider to display int or float attributes of partially specified classes. The upper and lower limits of slider can be set according to classes and attributes.
Realization
public class RangeAttribute : PropertyAttribute
{
public float min;
public float max;
public RangeAttribute(float min, float max)
{
this.min = min;
this.max = max;
}
}
[CustomPropertyDrawer(typeof(RangeAttribute))]
public class RangeDrawer : PropertyDrawer
{
// Draw the property inside the given rect
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// First get the attribute since it contains the range for the slider
RangeAttribute range = attribute as RangeAttribute;
// Now draw the property as a Slider or an IntSlider based on whether it's a float or integer.
if (property.propertyType == SerializedPropertyType.Float)
EditorGUI.Slider(position, property, range.min, range.max, label);
else if (property.propertyType == SerializedPropertyType.Integer)
EditorGUI.IntSlider(position, property, (int)range.min, (int)range.max, label);
else
EditorGUI.LabelField(position, label.text, "Use Range with float or int.");
}
}
Modify TestClass and DataClass
[CreateAssetMenu]
public class TestClass : ScriptableObject
{
[Range(0, 10)]
public int intData;
public string stringData;
public List<DataClass> dataList;
}
[System.Serializable]
public class DataClass
{
[Range(0, 100)]
public int id;
public Vector3 position;
public List<int> list;
}
Other
- All the classes that need to be modified to display need to be satisfied Unity's serialization rules
- These display modes can be used for Serializable Class, not necessarily scriptable Object. Just in the editor, it's common to use Scriptable Object to save temporary data, so use Scriptable Object as an example.
For reprinting, please indicate the source: http://blog.csdn.net/wuwangxinan/article/details/72773297