如何在CustomEditor中的嵌套ReorderableList中选择元素? [英] How to select elements in nested ReorderableList in a CustomEditor?

查看:217
本文介绍了如何在CustomEditor中的嵌套ReorderableList中选择元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 ReorderableList CustomEditor脚本中的a>.在drawElementCallback中,我添加了第二个嵌套的ReorderableList.一切正常,我可以在此处将元素添加到两个列表中

I have a ReorderableList in my CustomEditor script. In the drawElementCallback I added a second nested ReorderableList. Everything works fine and I can add elements to both lists like here

,由于某些原因,您无法选择内部ReorderableList的元素,因此也无法删除项目.

BUT as you can see for some reason I can not select the elements of the inner ReorderableLists so I also can not remove items.

如何在内部列表中选择项目?

将这些类分解为基本示例

Here the classes broken down to the basic example

using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;

[Serializable]
public class SomeClass
{
    public string Name;
    public List<SomeClass> InnerList;
}

[CreateAssetMenu(menuName = "Example", fileName = "new Example Asset")]
public class Example : ScriptableObject
{
    public List<SomeClass> SomeClasses;

    [CustomEditor(typeof(Example))]
    private class ModuleDrawer : Editor
    {
        private SerializedProperty SomeClasses;
        private ReorderableList list;

        private void OnEnable()
        {
            SomeClasses = serializedObject.FindProperty("SomeClasses");

            // setupt the outer list
            list = new ReorderableList(serializedObject, SomeClasses)
            {
                displayAdd = true,
                displayRemove = true,
                draggable = true,

                drawHeaderCallback = rect =>
                {
                    EditorGUI.LabelField(rect, "Outer List");
                },

                drawElementCallback = (rect, index, a, h) =>
                {
                    // get outer element
                    var element = SomeClasses.GetArrayElementAtIndex(index);

                    var InnerList = element.FindPropertyRelative("InnerList");

                    // Setup the inner list
                    var innerReorderableList = new ReorderableList(element.serializedObject, InnerList)
                    {
                        displayAdd = true,
                        displayRemove = true,
                        draggable = true,

                        drawHeaderCallback = innerRect =>
                        {
                            EditorGUI.LabelField(innerRect, "Inner List");
                        },

                        drawElementCallback = (innerRect, innerIndex, innerA, innerH) =>
                        {
                            // Get element of inner list
                            var innerElement = InnerList.GetArrayElementAtIndex(innerIndex);

                            var name = innerElement.FindPropertyRelative("Name");

                            EditorGUI.PropertyField(innerRect, name);
                        }
                    };

                    var height = (InnerList.arraySize + 3) * EditorGUIUtility.singleLineHeight;
                    innerReorderableList.DoList(new Rect(rect.x, rect.y, rect.width, height));
                },

                elementHeightCallback = index =>
                {
                    var element = SomeClasses.GetArrayElementAtIndex(index);

                    var innerList = element.FindPropertyRelative("InnerList");

                    return (innerList.arraySize + 4) * EditorGUIUtility.singleLineHeight;
                }
            };
        }

        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            list.DoLayoutList();

            serializedObject.ApplyModifiedProperties();
        }
    }
}


更新

如果我在CustomPropertyDrawer中有一个ReorderableList,同样显然也行不通.

The same apprantly also doesn't work if I have a ReorderableList within a CustomPropertyDrawer.

但是让我惊讶的是,如果我有 UnityEvent 均有效:将其放在CustomPropertyDrawer内或ReorderableList内.我可以按预期添加和删除项目.

But to my suprise if I have a UnityEvent both works: Having it inside a CustomPropertyDrawer or within a ReorderableList. I can add and remove items as expected.

如您所见,我通过添加

[Serializable]
public class SomeClass
{
    public string Name;
    public List<SomeClass> InnerList;
}

并使用

//...
innerReorderableList.DoList(new Rect(rect.x, rect.y, rect.width, height));

var InnerEvent = element.FindPropertyRelative("InnerEvent");
var pers = InnerEvent.FindPropertyRelative("m_PersistentCalls.m_Calls");
var evHeight = (Mathf.Max(1, pers.arraySize) * 2 + 3) * EditorGUIUtility.singleLineHeight;
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, evHeight), InnerEvent);

,然后将elementHeightCallback调整为

elementHeightCallback = index =>
{
    var element = SomeClasses.GetArrayElementAtIndex(index);

    var innerList = element.FindPropertyRelative("InnerList");
    var InnerEvent = element.FindPropertyRelative("InnerEvent");
    var pers = InnerEvent.FindPropertyRelative("m_PersistentCalls.m_Calls");

    return (Mathf.Max(1, innerList.arraySize) + 4 + Mathf.Max(1, pers.arraySize) * 2 + 4) * EditorGUIUtility.singleLineHeight;
}

我可以按预期与之完全交互,并且可以选择和删除条目.

I can fully interact with it as expected and also select and remove entries.

那他们有什么不同?

推荐答案

似乎您是一遍又一遍地创建内部列表,而没有将它们存储在任何地方.我修改了您的代码以将可重新排序的列表存储在以element.propertyPath为键的字典中.希望这会有所帮助.

It looks like you are creating the inner lists over and over without storing them anywhere. I modified your code to store the reorderable lists in a dictionary with the element.propertyPath as a key. Hope this helps.

using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;

[Serializable]
public class SomeClass
{
    public string Name;
    public List<SomeClass> InnerList;
}

[CreateAssetMenu(menuName = "Example", fileName = "new Example Asset")]
public class Example : ScriptableObject
{
    public List<SomeClass> SomeClasses;

    [CustomEditor(typeof(Example))]
    private class ModuleDrawer : Editor
    {
        private SerializedProperty SomeClasses;
        private ReorderableList list;

        private Dictionary<string, ReorderableList> innerListDict = new Dictionary<string, ReorderableList>();

        private void OnEnable()
        {
            SomeClasses = serializedObject.FindProperty("SomeClasses");

            // setupt the outer list
            list = new ReorderableList(serializedObject, SomeClasses)
            {
                displayAdd = true,
                displayRemove = true,
                draggable = true,

                drawHeaderCallback = rect =>
                {
                    EditorGUI.LabelField(rect, "Outer List");
                },

                drawElementCallback = (rect, index, a, h) =>
                {
                    // get outer element
                    var element = SomeClasses.GetArrayElementAtIndex(index);

                    var InnerList = element.FindPropertyRelative("InnerList");

                    string listKey = element.propertyPath;

                    ReorderableList innerReorderableList;

                    if (innerListDict.ContainsKey(listKey))
                    {
                        // fetch the reorderable list in dict
                        innerReorderableList = innerListDict[listKey];
                    }
                    else
                    {
                        // create reorderabl list and store it in dict
                        innerReorderableList = new ReorderableList(element.serializedObject, InnerList)
                        {
                            displayAdd = true,
                            displayRemove = true,
                            draggable = true,

                            drawHeaderCallback = innerRect =>
                            {
                                EditorGUI.LabelField(innerRect, "Inner List");
                            },

                            drawElementCallback = (innerRect, innerIndex, innerA, innerH) =>
                            {
                                // Get element of inner list
                                var innerElement = InnerList.GetArrayElementAtIndex(innerIndex);

                                var name = innerElement.FindPropertyRelative("Name");

                                EditorGUI.PropertyField(innerRect, name);
                            }
                        };
                        innerListDict[listKey] = innerReorderableList;
                    }

                    // Setup the inner list
                    var height = (InnerList.arraySize + 3) * EditorGUIUtility.singleLineHeight;
                    innerReorderableList.DoList(new Rect(rect.x, rect.y, rect.width, height));
                },

                elementHeightCallback = index =>
                {
                    var element = SomeClasses.GetArrayElementAtIndex(index);

                    var innerList = element.FindPropertyRelative("InnerList");

                    return (innerList.arraySize + 4) * EditorGUIUtility.singleLineHeight;
                }
            };
        }

        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            list.DoLayoutList();

            serializedObject.ApplyModifiedProperties();
        }
    }
}

这篇关于如何在CustomEditor中的嵌套ReorderableList中选择元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆