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

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

问题描述

我有一个

BUT 正如您所看到的,由于某种原因我无法选择内部 ReorderableList 的元素,因此我也无法删除项目.

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

<小时>

这里的类分解为基本示例

使用系统;使用 System.Collections.Generic;使用 UnityEditor;使用 UnityEditorInternal;使用 UnityEngine;[可序列化]公共类 SomeClass{公共字符串名称;公共列表内部列表;}[CreateAssetMenu(menuName = "Example", fileName = "new Example Asset")]公共类示例:ScriptableObject{公共列表一些类;[自定义编辑器(typeof(Example))]私有类 ModuleDrawer :编辑器{私有 SerializedProperty SomeClasses;私有 ReorderableList 列表;私有无效 OnEnable(){SomeClasses = serializedObject.FindProperty("SomeClasses");//设置外部列表list = new ReorderableList(serializedObject, SomeClasses){显示添加 = 真,displayRemove = 真,可拖动 = 真,drawHeaderCallback = rect =>{EditorGUI.LabelField(rect, "外部列表");},drawElementCallback = (rect, index, a, h) =>{//获取外部元素var element = SomeClasses.GetArrayElementAtIndex(index);var InnerList = element.FindPropertyRelative("InnerList");//设置内部列表var innerReorderableList = new ReorderableList(element.serializedObject, InnerList){显示添加 = 真,displayRemove = 真,可拖动 = 真,drawHeaderCallback = innerRect =>{EditorGUI.LabelField(innerRect, "内部列表");},drawElementCallback = (innerRect,innerIndex,innerA,innerH) =>{//获取内部列表的元素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 = 索引 =>{var element = SomeClasses.GetArrayElementAtIndex(index);var innerList = element.FindPropertyRelative("InnerList");返回 (innerList.arraySize + 4) * EditorGUIUtility.singleLineHeight;}};}公共覆盖无效 OnInspectorGUI(){serializedObject.Update();list.DoLayoutList();serializedObject.ApplyModifiedProperties();}}}

<小时>

更新

如果我在 CustomPropertyDrawer 中有一个 ReorderableList,同样的方法也不起作用.

但是如果我有一个

那么他们的做法有何不同?

解决方案

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

使用系统;使用 System.Collections.Generic;使用 UnityEditor;使用 UnityEditorInternal;使用 UnityEngine;[可序列化]公共类 SomeClass{公共字符串名称;公共列表内部列表;}[CreateAssetMenu(menuName = "Example", fileName = "new Example Asset")]公共类示例:ScriptableObject{公共列表一些类;[自定义编辑器(typeof(Example))]私有类 ModuleDrawer :编辑器{私有 SerializedProperty SomeClasses;私有 ReorderableList 列表;私有字典innerListDict = new Dictionary();私有无效 OnEnable(){SomeClasses = serializedObject.FindProperty("SomeClasses");//设置外部列表list = new ReorderableList(serializedObject, SomeClasses){显示添加 = 真,displayRemove = 真,可拖动 = 真,drawHeaderCallback = rect =>{EditorGUI.LabelField(rect, "外部列表");},drawElementCallback = (rect, index, a, h) =>{//获取外部元素var element = SomeClasses.GetArrayElementAtIndex(index);var InnerList = element.FindPropertyRelative("InnerList");字符串 listKey = element.propertyPath;ReorderableList innerReorderableList;if (innerListDict.ContainsKey(listKey)){//获取 dict 中的可重排序列表innerReorderableList = innerListDict[listKey];}别的{//创建可重新排序的列表并将其存储在字典中innerReorderableList = new ReorderableList(element.serializedObject, InnerList){显示添加 = 真,displayRemove = 真,可拖动 = 真,drawHeaderCallback = innerRect =>{EditorGUI.LabelField(innerRect, "内部列表");},drawElementCallback = (innerRect,innerIndex,innerA,innerH) =>{//获取内部列表的元素var innerElement = InnerList.GetArrayElementAtIndex(innerIndex);var name = innerElement.FindPropertyRelative("Name");EditorGUI.PropertyField(innerRect, name);}};innerListDict[listKey] = innerReorderableList;}//设置内部列表var height = (InnerList.arraySize + 3) * EditorGUIUtility.singleLineHeight;innerReorderableList.DoList(new Rect(rect.x, rect.y, rect.width, height));},elementHeightCallback = 索引 =>{var element = SomeClasses.GetArrayElementAtIndex(index);var innerList = element.FindPropertyRelative("InnerList");返回 (innerList.arraySize + 4) * EditorGUIUtility.singleLineHeight;}};}公共覆盖无效 OnInspectorGUI(){serializedObject.Update();list.DoLayoutList();serializedObject.ApplyModifiedProperties();}}}

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

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.

How can I select items in the inner list?


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


Update

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

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.

As you can see here I added a UnityEvent field by adding

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

and using

//...
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);

and adjusting the elementHeightCallback to

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.

So what are they doing different?

解决方案

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

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

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