有时,您有包含数据但不从MonoBehaviour派生的自定义对象。除非您为对象类型编写自己的自定义属性抽屉,否则将这些对象添加为MonoBehaviour类中的字段不会产生视觉效果。
下面是添加到MonoBehaviour的自定义对象的简单示例,以及该自定义对象的自定义属性抽屉。
public enum Gender {
Male,
Female,
Other
}
// 需要Serializable属性,否则将不使用CustomPropertyDrawer
[Serializable]
public class UserInfo {
public string Name;
public int Age;
public Gender Gender;
}
// 您可以附加到GameObject的类
public class PropertyDrawerExample : MonoBehaviour {
public UserInfo UInfo;
}
[CustomPropertyDrawer( typeof( UserInfo ) )]
public class UserInfoDrawer : PropertyDrawer {
public override float GetPropertyHeight( SerializedProperty property, GUIContent label ) {
// 6来自字段之间的额外间距(每个2px)
returnEditorGUIUtility.singleLineHeight* 4 + 6;
}
public override void OnGUI( Rect position, SerializedProperty property, GUIContent label ) {
EditorGUI.BeginProperty( position, label, property );
EditorGUI.LabelField( position, label );
var nameRect = new Rect( position.x,position.y+ 18, position.width, 16 );
var ageRect = new Rect( position.x,position.y+ 36, position.width, 16 );
var genderRect = new Rect( position.x,position.y+ 54, position.width, 16 );
EditorGUI.indentLevel++;
EditorGUI.PropertyField( nameRect, property.FindPropertyRelative( "Name" ) );
EditorGUI.PropertyField( ageRect, property.FindPropertyRelative( "Age" ) );
EditorGUI.PropertyField( genderRect, property.FindPropertyRelative( "Gender" ) );
EditorGUI.indentLevel--;
EditorGUI.EndProperty();
}
}首先,我们定义具有所有要求的自定义对象。只是描述用户的简单类。该类在我们的PropertyDrawerExample类中使用,可以将其添加到GameObject中。
public enum Gender {
Male,
Female,
Other
}
[Serializable]
public class UserInfo {
public string Name;
public int Age;
public Gender Gender;
}
public class PropertyDrawerExample : MonoBehaviour {
public UserInfo UInfo;
}自定义类需要Serializable属性,否则将不使用CustomPropertyDrawer
接下来是CustomPropertyDrawer
首先,我们必须定义一个从PropertyDrawer派生的类。类定义还需要CustomPropertyDrawer属性。传递的参数是您希望此抽屉用于的对象的类型。
[CustomPropertyDrawer( typeof( UserInfo ) )]
public class UserInfoDrawer : PropertyDrawer {接下来,我们重写GetPropertyHeight函数。这使我们可以为属性定义自定义高度。在这种情况下,我们知道我们的财产将分为四个部分:标签,姓名,年龄和性别。因此,我们使用EditorGUIUtility.singleLineHeight * 4,我们又添加了6个像素,因为我们希望每个字段之间用两个像素隔开。
public override float GetPropertyHeight( SerializedProperty property, GUIContent label ) {
returnEditorGUIUtility.singleLineHeight* 4 + 6;
}接下来是实际的OnGUI方法。我们从EditorGUI.BeginProperty([...])开始,然后以结束函数。我们这样做是为了如果此属性成为预制件的一部分,则实际的预制件覆盖逻辑将适用于这两种方法之间的所有内容。EditorGUI.EndProperty()
public override void OnGUI( Rect position, SerializedProperty property, GUIContent label ) {
EditorGUI.BeginProperty( position, label, property );之后,我们显示一个包含字段名称的标签,并且我们已经为字段定义了矩形。
EditorGUI.LabelField( position, label ); var nameRect = new Rect( position.x,position.y+ 18, position.width, 16 ); var ageRect = new Rect( position.x,position.y+ 36, position.width, 16 ); var genderRect = new Rect( position.x,position.y+ 54, position.width, 16 );
每个字段间隔为16 + 2像素,高度为16(与EditorGUIUtility.singleLineHeight相同)
接下来,我们使用一个选项卡对UI进行缩进,以获得更好的布局,显示属性,取消对GUI的缩进,并以EditorGUI.EndProperty结尾。
EditorGUI.indentLevel++; EditorGUI.PropertyField( nameRect, property.FindPropertyRelative( "Name" ) ); EditorGUI.PropertyField( ageRect, property.FindPropertyRelative( "Age" ) ); EditorGUI.PropertyField( genderRect, property.FindPropertyRelative( "Gender" ) ); EditorGUI.indentLevel--; EditorGUI.EndProperty();
我们使用EditorGUI.PropertyField来显示字段,该字段需要一个矩形作为位置,并需要SerializedProperty作为显示的属性。我们通过在OnGUI函数中传递的属性上调用FindPropertyRelative(“ ...”)来获取属性。请注意,这些是区分大小写的,并且找不到非公共属性!
对于此示例,我没有保存从property.FindPropertyRelative(“ ...”)返回的属性。您应该将它们保存在类的私有字段中,以防止不必要的调用
结果
之前
后