うにてぃブログ

主にUnityとC#に関する記事を書いていきます

【Unity】ReorderableList の GUI を作り変える

ReorderableList のデフォルト GUI は右下に + と - があり
削除する際は要素を選択してから - を押す必要があり面倒だったので、GUI を変更してみました

f:id:hacchi_man:20200724165054p:plain:w350

using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
 
public class SampleMonoBehaviour : MonoBehaviour
{
    [SerializeField]
    private GameObject[] _list;
}

[CustomEditor(typeof(SampleMonoBehaviour))]
public class SampleMonoBehaviourEditor : Editor
{
    private ReorderableList reorderable;
 
    private void OnEnable()
    {
        var list = serializedObject.FindProperty("_list");
        reorderable = new ReorderableList(serializedObject, list)
        {
            drawElementCallback = (rect, index, isActive, isFocused) => EditorGUI.PropertyField(rect, _list.GetArrayElementAtIndex(index))
        };
    }
 
    public override void OnInspectorGUI()
    {
        reorderable.DoLayoutList();
    }
}

GUI 改修

各要素の横に - ボタンを設置し削除する際に 1クリックでできるようにし
+ をフッターに置く必要が無かったので、右上に設置してあります

f:id:hacchi_man:20200724024020p:plain:w350

コード

using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
 
public class CustomReorderable
{
    private static class Style
    {
        public static GUIContent AddContent;
        public static GUIStyle AddStyle;
        public static GUIContent SubContent;
        public static GUIStyle SubStyle;

        static Style()
        {
            AddContent = EditorGUIUtility.TrIconContent("Toolbar Plus", "Add to list");
            AddStyle = "RL FooterButton";


            SubContent = EditorGUIUtility.TrIconContent("Toolbar Minus", "Remove selection from list");
            SubStyle = "RL FooterButton";
        }
    }
    private ReorderableList reorderableList;


    public CustomReorderable(SerializedProperty property)
    {
        reorderableList = CreateInstance(property);
    }

    public void Draw()
    {
        reorderableList.DoLayoutList();
    }

    private ReorderableList CreateInstance(SerializedProperty property)
    {
        return new ReorderableList(property.serializedObject, property, true, true, false, false)
        {
            drawHeaderCallback = rect =>
            {
                EditorGUI.LabelField(rect, $"{property.displayName}: {property.arraySize}", EditorStyles.boldLabel);
                var position =
                    new Rect(
                        rect.width - (EditorGUI.indentLevel - property.depth) * 15f,
                        rect.y,
                        20f,
                        13f
                    );
                if (GUI.Button(position, Style.AddContent, Style.AddStyle))
                {
                    property.serializedObject.UpdateIfRequiredOrScript();
                    property.InsertArrayElementAtIndex(property.arraySize);
                    property.serializedObject.ApplyModifiedProperties();
                }
            },
            drawElementCallback = (rect, index, isActive, isFocused) =>
            {
                if (property.arraySize <= index)
                    return;
 
                DrawElement(property, rect, index);
 
                rect.xMin = rect.width + 20f - (EditorGUI.indentLevel - property.depth) * 15f;
                rect.width = 20f;
                if (GUI.Button(rect, Style.SubContent, Style.SubStyle))
                {
                    property.serializedObject.UpdateIfRequiredOrScript();
                    property.DeleteArrayElementAtIndex(index);
                    property.serializedObject.ApplyModifiedProperties();
                }
            },
 
            drawFooterCallback = rect => { },
            footerHeight = 0f,
            elementHeightCallback = index =>
            {
                if (property.arraySize <= index)
                    return 0;
 
                return EditorGUI.GetPropertyHeight(property.GetArrayElementAtIndex(index));
            }
        };
    }

    private void DrawElement(SerializedProperty property, Rect rect, int index)
    {
        var indexName = index.ToString();
 
        rect.x += 5f;
        rect.width -= 25f;
        var elementProperty = property.GetArrayElementAtIndex(index);
        if (elementProperty.propertyType != SerializedPropertyType.Generic)
        {
            EditorGUI.PropertyField(rect, elementProperty, new GUIContent(indexName));
            return;
        }
 
        rect.x += 10f;
        rect.width -= 20f;
        rect.height = EditorGUIUtility.singleLineHeight;
 
        elementProperty.isExpanded = EditorGUI.Foldout(rect, elementProperty.isExpanded, new GUIContent(indexName));
        rect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
 
        if (!elementProperty.isExpanded)
            return;
        
        var depth = -1;
        while (elementProperty.NextVisible(true) || depth == -1)
        {
            if (depth != -1 && elementProperty.depth != depth)
                break;

            depth = elementProperty.depth;
            rect.height = EditorGUI.GetPropertyHeight(elementProperty);
            EditorGUI.PropertyField(rect, elementProperty, true);
            rect.y += rect.height;
        }
    }
}