如何使用onAddCallBack将最新添加的项目设置为ReorderableList的默认项目?

时间:2019-07-08 23:18:40

标签: c# unity3d

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

[CustomEditor(typeof(ConversationTrigger))]
public class ConversationTriggerEditor : Editor
{
    private Vector2 scrollPos;
    private SerializedProperty conversations;
    private ConversationTrigger conversationTrigger;
    private ReorderableList conversationList;

    private void OnEnable()
    {
        conversations = serializedObject.FindProperty("conversations");
        conversationTrigger = (ConversationTrigger)target;        

        conversationList = new ReorderableList(serializedObject, conversations)
        {
            displayAdd = true,
            displayRemove = true,
            draggable = true,

            onAddCallback = addcallback =>
            {
                addcallback.list[addcallback.list.Count] = default;
            },

            drawElementCallback = (rect, index, isActive, isSelected) =>
            {
                var element = conversations.GetArrayElementAtIndex(index);

                var name = element.FindPropertyRelative("Name");
                // do this for all properties

                var position = EditorGUI.PrefixLabel(rect, new GUIContent(name.stringValue));

                EditorGUI.PropertyField(position, name);
            },

            elementHeight = EditorGUIUtility.singleLineHeight
        };
    }

    public override void OnInspectorGUI()
    {
        // Load the current values from the real component into the serialized copy
        serializedObject.Update();

        EditorGUILayout.LabelField("Conversations", EditorStyles.boldLabel);
        var newSize = EditorGUILayout.IntField(conversations.arraySize);
        conversations.arraySize = Mathf.Max(0, newSize);

        scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.Height(250));

        GUILayout.Space(10);
        conversationList.DoLayoutList();

        EditorGUILayout.EndScrollView();

        if (GUILayout.Button("Add new conversation"))
        {
            conversations.arraySize++;
        }

        GUILayout.Space(10);
        if (conversations.arraySize != 0)
        {
            if (GUILayout.Button("Remove conversation"))
            {
                if (conversations.arraySize > 0) conversations.arraySize--;
            }
        }

        GUILayout.Space(100);
        if (GUILayout.Button("Save Conversations"))
        {
            conversationTrigger.SaveConversations();
        }

        GUILayout.Space(10);
        if (GUILayout.Button("Load Conversations"))
        {
            Undo.RecordObject(conversationTrigger, "Loaded conversations from JSON");
            conversationTrigger.LoadConversations();
        }

        serializedObject.ApplyModifiedProperties();
    }
}

主要有两个问题:

首先:属性displayAdd和displayRemove必须为true才能使用onAddCallback。也许只有displayAdd必须为true。如果它是错误的,我使用了一个断点,它永远不会到达终点:

addcallback.list[addcallback.list.Count] = default;

如果都为true,则转到此行,但想法是将最新添加的项目设置为ReorderableList,使其默认为空而没有名称,因为现在添加新的对话时,它会复制最后一个项目。相反,我想添加一个新的空项目。

第二条:即使到达该行,该行也无法正常工作,它一直无济于事,不断添加重复项:

addcallback.list[addcallback.list.Count] = default;

当displayAdd和displayRemove均为false时,如何使用onAddCallback?我希望它们是假的,因为我在伪造使用两个按钮的添加/删除。 但是,如果它们为假,则无法使用onAddCallback

以及如何设置和添加新项目时将其命名为空?

1 个答案:

答案 0 :(得分:1)

一旦覆盖onAddCallback,就必须积极增加arraySize,如果不覆盖它,这是默认行为。

                // you don't have to go through the list property
                // you could ofcourse but anyway you already know which list
                // you want to change
onAddCallback = list =>
{
    // first add one element
    conversations.arraySize++;
    // then get that element
    var newIndex = conversations.arraySize - 1;
    var newElement = conversations.GetArrayElementAtIndex(newIndex);

    // now reset all properties like
    var name = newElement.FindPropertyRelative("Name");
    name.stringValue = "";

    // ...
},

请注意,这无法与您的

一起使用
GUILayout.Button("Add new conversation")

也不通过

添加新元素
EditorGUILayout.IntField(conversations.arraySize);

首先,您可以简单地像

if(GUILayout.Button("Add new conversation"))
{
    // first add one element
    conversations.arraySize++;
    // then get that element
    var newIndex = conversations.arraySize - 1;
    var newElement = conversations.GetArrayElementAtIndex(newIndex);

    // now reset all properties like
    var name = newElement.FindPropertyRelative("Name");
    name.stringValue = "";
}

第二秒钟,您必须检查是否删除了元素或添加了元素以及数量:

EditorGUI.BeginChangeCheck();
{
    var newSize = EditorGUILayout.IntField(conversations.arraySize);
}
if(EditorGUI.EndChangeCheck())
{
    if(newSize > conversations.arraySize)
    {
        // elements have to be added -> how many?
        var toAdd = newSize - conversations.arraySize - 1;
        // why -1 ? -> We add the first element and set its values to default
        // now if we simply increase the arraySize for the rest of the elements
        // they will be all a copy of the first -> all defaults ;)

        // first add one element
        conversations.arraySize++;
        // then get that element
        var newIndex = conversations.arraySize - 1;
        var newElement = conversations.GetArrayElementAtIndex(newIndex);

        // now reset all properties like
        var name = newElement.FindPropertyRelative("Name");
        name.stringValue = "";

        // now for the rest simply increase arraySize
        conversations.arraySize += toAdd;
    }
    else
    {
        // for removing just make sure the arraySize is not under 0
        conversations.arraySize = Mathf.Max(newSize, 0);
    }
}

不幸的是,Unity EditorScripting就是这样。直到现在,它仍然很糟糕并且变得非常复杂,只是为了获得所需的布局;)

但是他们正在努力,新的alpha和beta版本2019.2和2019.3已经提供了新的Inspector和Unity GUI的一些预览,并且可能会有更简单的方法来进行编辑器设计...;)