Как правильно отрисовывать CustomPropertyDrawer
Встала необходимость отрисовывать в редакторе сериализуемые классы определённым образом.
Есть кастомный редактор для объекта, который имеет вид:

Рисуются построчно одиночные поля и массивы, за ними есть 3 кнопки. Всё хорошо и замечательно.
Пробую сделать то же самое, но отрисовку полей и массивов делаю с помощью CustomPropertyDrawer. Сразу же натыкаюсь на такое:
То есть отрисовывается проперти, внутри которого отступы нормальные, а когда очередь доходит до отрисовки кнопок, они отрисовываются поверх, как будто весь проперти занимал 1 строку,а не несколько. Как с этим бороться? Блок кода редактора, где рисуется проперти и кнопки:
var prop = serializedObject.FindProperty(nameof(crt.displayedDimension));
PropertyField(prop);
serializedObject.ApplyModifiedProperties();
BeginHorizontal("box");
if (GUILayout.Button("Copy dimension"))
{
copyMatrix = new MatrixDimension<T>(cr.Dimensions[cr.currentDimensionIndex]);
}
if (GUILayout.Button("Paste copied dimension"))
{
confirmPressed = !confirmPressed;
if (copyMatrix != null)
onPress = () => { cr.Dimensions[cr.currentDimensionIndex] = new MatrixDimension<T>(copyMatrix); };
}
if (GUILayout.Button("Clear dimension"))
{
confirmPressed = !confirmPressed;
onPress = () => { cr.Dimensions[cr.currentDimensionIndex] = new MatrixDimension<T>(cr.ColumnsCount); };
}
EndHorizontal();
Код отрисовки проперти:
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
float space = 2f;
float labelSize = 150f;
var scaleFloat = property.FindPropertyRelative("scallingValue");
var dimensionName = property.FindPropertyRelative("dimensionName");
var namesArr = property.FindPropertyRelative("columnsNames.vector");
BeginProperty(position, label, property);
scaleFloat.floatValue = FloatField(position, new GUIContent("Dimension scale"), scaleFloat.floatValue);
position.y += position.height + space;
dimensionName.stringValue = TextField(position, new GUIContent("Dimension name"), dimensionName.stringValue);
position.y += position.height + space;
position = DrawArrayOneLine(position, labelSize,string.Empty, namesArr);
EndProperty();
property.serializedObject.ApplyModifiedProperties();
}
Ответы (2 шт):
Решение найдено. Необходимо было переопределить GetPropertyHeigh в Drawer'е чтобы итоговый размер Rect для проперти был достаточный для отрисовки полей.
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
var totalLines = 51;
return totalLines * EditorGUIUtility.singleLineHeight + verticalSpace * (totalLines -1);
}
Хороший тутор по теме: https://nosuchstudio.medium.com/learn-unity-editor-scripting-property-drawers-part-2-6fe6097f1586
Да, GUILayout отрисовывает все в Editor по строчно сам следя за шириной и позицией, но в PropertyDrawer такой роскоши нет, ширина/высота/позиция прописывается вручную.
Высота поля определяется через метод GetPropertyHeight.
public override float GetPropertyHeight (SerializedProperty property, GUIContent label)
{
int lineCount = 3;
if (property.isExpanded)
return EditorGUIUtility.singleLineHeight*lineCount+
EditorGUIUtility.standardVerticalSpacing*(lineCount-1);
else
return EditorGUIUtility.singleLineHeight;
}
Причем в зависимости от того свернуто поле объекта или нет, она разная. Статус свернутости определяется значением SerializedProperty.isExpanded.
Для правильной размерности полезны стандартные значения:
EditorGUIUtility.singleLineHeightстандартная высота строки редактораEditorGUIUtility.standardVerticalSpacingстандартный пробел между строкамиEditorGUIUtility.currentViewWidthтекущая ширина окна (инспектора в данном контексте). Но вPropertyDrawerкоректнее использоватьSerializedProperty.width.
EditorGUI.BeginProperty(position, label, property);
position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
var labelRect1 = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
position.y += EditorGUIUtility.singleLineHeigh+EditorGUIUtility.standardVerticalSpacing;
var labelRect2 = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
position.y += EditorGUIUtility.singleLineHeigh+EditorGUIUtility.standardVerticalSpacing;
var labelRect3 = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
И все будет выглядеть словно отрисовывал GUILayout.
Не забываем про документацию . По поиску height, можно было найти ответ.
