Как я могу использовать onAddCallBack, чтобы сделать новые добавленные элементы в ReorderableList по умолчанию? - PullRequest
0 голосов
/ 09 июля 2019
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;

Как я могу использовать onAddCallback, когда displayAdd и displayRemove имеют значение false? Я хочу, чтобы они были ложными, поскольку я притворяюсь добавлять / удалять, используя две кнопки Но если они ложные, я не могу использовать onAddCallback

А как установить и сделать так, чтобы при добавлении нового элемента он был пустым без имени?

1 Ответ

1 голос
/ 09 июля 2019

После того, как вы переопределите 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 это не так .. до сих пор это отстой и становится очень сложным, просто чтобы получить нужный макет;)

Но они работают над этим, и новые альфа- и бета-версии 2019.2 и 2019.3 уже дают некоторые предварительные обзоры нового Inspector и Unity GUI, и в скором времени может появиться более простой способ создания конструкций Editor ...;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...