unity3d-reorderable-list icon indicating copy to clipboard operation
unity3d-reorderable-list copied to clipboard

Reordable lists of custom serializable object don't respect item size

Open fabiopolimeni opened this issue 6 years ago • 1 comments

Hi,

I was trying to use your plugin to show some Serializable item, but the height of the displayed list item doesn't respect the item.

reordablelist-default

And this is the simple code to generate this.

WordPicker.cs

    [CreateAssetMenu(fileName = "WordPicker", menuName = "Quest/WordPicker", order = 3)]
    public class WordPicker : ScriptableObject
    {
            [System.Serializable]
            public class Choice
	    {
		    [Tooltip("Possible valid words/senteces, separated by commas ','")]
		    public string valids;
            
		    [Tooltip("Possible invalid words/strings, separated by commas ','")]
                    public string invalids;
             }

	    [TextArea(3, 10)]
	    public string phrase;
	    
	    [Tooltip("List of valid and invlid words/strings")]
	    public List<Choice> choices;
    }

WordPickerEditor.cs

    [CustomPropertyDrawer(typeof(WordPicker.Choice))]
    public class Drawer : PropertyDrawer
    {
        // Draw the property inside the given rect
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
                // Using BeginProperty / EndProperty on the parent property means that
                // prefab override logic works on the entire property.
                EditorGUI.BeginProperty(position, label, property);

                // Draw label
	        position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);

                // Don't make child fields be indented
                var indent = EditorGUI.indentLevel;
                EditorGUI.indentLevel = 0;
            
	        // Draw fields - passs GUIContent.none to each so they are drawn without labels
	        Rect validPos = position;
	        var validProp = property.FindPropertyRelative("valids");
	        var validLabel = new GUIContent("Valid words");
	        EditorGUI.PropertyField(validPos, validProp, validLabel);
	        
	        float validHeight = EditorGUI.GetPropertyHeight(validProp, validLabel, true);
	        
	        Rect invalidPos = validPos;
	        invalidPos.y += validHeight;
	        
	        EditorGUI.PropertyField(invalidPos, property.FindPropertyRelative("invalids"), new GUIContent("Invalid words"));

                // Set indent back to what it was
                EditorGUI.indentLevel = indent;

                EditorGUI.EndProperty();
        }
    }

	//[CanEditMultipleObjects]
	[CustomEditor(typeof(WordPicker))]
        public class WordPickerEditor : UnityEditor.Editor
	{
		private SerializedProperty _phraseProperty;
                private SerializedProperty _listProperty;
                private ReorderableListControl _listControl;
                private IReorderableListAdaptor _listAdaptor;

                private void OnEnable()
		{
			_phraseProperty = serializedObject.FindProperty("phrase");
                        _listControl = new ReorderableListControl();
			_listProperty = serializedObject.FindProperty("choices");
                       _listAdaptor = new SerializedPropertyAdaptor(_listProperty);
                }

	        public override void OnInspectorGUI()
                {
                       serializedObject.Update();
                       _listControl.Draw(_listAdaptor);
                       serializedObject.ApplyModifiedProperties();
                }
       }

Even if I try to set the list item height manually e.g. ReorderableListGUI.ListField(_listProperty, 36f); (not desired anyway), the first item will be stretched to cover the whole height, overlapping the second.

What am I doing wrong?

Once we are here, I have tried to use ReorderableListAttribute with no luck, I couldn't find the way of using this. Would you mind to provide a simple example? Maybe to apply in this case, as far as I understand this can potentially reduce the amount of code I need to write to make the reordable-list work nicely.

Thanks, Fabio

fabiopolimeni avatar Mar 06 '18 17:03 fabiopolimeni

The issue is inside your custom property drawer. Unity provides two methods that should be overridden; GetPropertyHeight and OnGUI.

So in your case, something like this (not tested):

    [CustomPropertyDrawer(typeof(WordPicker.Choice))]
    public class Drawer : PropertyDrawer
    {
        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
	        var validProp = property.FindPropertyRelative("valids");
	        var invalidProp = property.FindPropertyRelative("invalids");
                return EditorGUI.GetPropertyHeight(validProp, GUIContent.none, true)
                     + EditorGUI.GetPropertyHeight(invalidProp , GUIContent.none, true); 
        }

        // Draw the property inside the given rect
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
                // Using BeginProperty / EndProperty on the parent property means that
                // prefab override logic works on the entire property.
                EditorGUI.BeginProperty(position, label, property);

                // Draw label
	        position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);

                // Don't make child fields be indented
                var indent = EditorGUI.indentLevel;
                EditorGUI.indentLevel = 0;
            
	        // Draw fields - passs GUIContent.none to each so they are drawn without labels
	        Rect validPos = position;
	        var validProp = property.FindPropertyRelative("valids");
	        var validLabel = new GUIContent("Valid words");
	        EditorGUI.PropertyField(validPos, validProp, validLabel);
	        
	        float validHeight = EditorGUI.GetPropertyHeight(validProp, validLabel, true);
	        
	        Rect invalidPos = validPos;
	        invalidPos.y += validHeight;
	        
	        EditorGUI.PropertyField(invalidPos, property.FindPropertyRelative("invalids"), new GUIContent("Invalid words"));

                // Set indent back to what it was
                EditorGUI.indentLevel = indent;

                EditorGUI.EndProperty();
        }
    }

kruncher avatar May 06 '18 13:05 kruncher