如何在自定义编辑器的嵌套 ReorderableList 中选择元素? [英] How to select elements in nested ReorderableList in a CustomEditor?
问题描述
我有一个
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 ReorderableList
s 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屋!