rotorz / unity3d-reorderable-list

List control for Unity allowing editor developers to add reorderable list controls to their GUIs.
MIT License
169 stars 31 forks source link

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

Open fabiopolimeni opened 6 years ago

fabiopolimeni commented 6 years ago

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

kruncher commented 6 years ago

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();
        }
    }