Personalização da Visualização de Arrays no Inspector do Unity

No desenvolvimento com Unity, é possível personalizar a exibição de arrays no Inspector utilizando scripts do editor. A seguir, apresenta-se um exemplo prático.

Definição de Classe Personalizada

[System.Serializable]
public class Pessoa
{
    public string nome;
    public int idade;
}

Classe de Dados com ScriptableObject

using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu]
public class DadosPessoa : ScriptableObject
{
    public List<Pessoa> listaPessoas;
}

Exibição em Uma Única Linha por Elemento

Para exibir o conteúdo de cada elemanto em uma linha, é necessário criar um PropertyDrawer. Note que a API de layout automático não deve ser usada neste caso.

using UnityEngine;
using UnityEditor;

[CustomPropertyDrawer(typeof(Pessoa))]
public class PessoaDrawer : PropertyDrawer
{
    public override void OnGUI(Rect posicao, SerializedProperty propriedade, GUIContent etiqueta)
    {
        var spNome = propriedade.FindPropertyRelative("nome");
        var spIdade = propriedade.FindPropertyRelative("idade");

        var retangulo1 = new Rect(posicao.x, posicao.y, posicao.width * 0.5f, EditorGUIUtility.singleLineHeight);
        var retangulo2 = new Rect(posicao.x + posicao.width * 0.5f + 40, posicao.y, posicao.width * 0.5f, EditorGUIUtility.singleLineHeight);

        int nivelIndentacao = EditorGUI.indentLevel;
        float larguraEtiqueta = EditorGUIUtility.labelWidth;

        EditorGUI.indentLevel = 2;
        EditorGUIUtility.labelWidth = 60;

        EditorGUI.PropertyField(retangulo1, spNome, new GUIContent("Nome"));
        EditorGUI.PropertyField(retangulo2, spIdade, new GUIContent("Idade"));

        EditorGUI.indentLevel = nivelIndentacao;
        EditorGUIUtility.labelWidth = larguraEtiqueta;
    }

    public override float GetPropertyHeight(SerializedProperty propriedade, GUIContent etiqueta)
    {
        return base.GetPropertyHeight(propriedade, etiqueta);
    }
}

Personalização do Nome da Lista e dos Elementos

Para alterar o nome exibido da lista e dos elementos, pode-se implementar um editor personalizado utilizando ReorderableList.

using UnityEngine;
using UnityEditor;
using UnityEditorInternal;

[CustomEditor(typeof(DadosPessoa))]
public class DadosPessoaEditor : Editor
{
    private SerializedProperty propriedadeLista;
    private ReorderableList listaReordenavel;

    private void OnEnable()
    {
        propriedadeLista = serializedObject.FindProperty("listaPessoas");

        if (listaReordenavel == null)
        {
            listaReordenavel = new ReorderableList(serializedObject, propriedadeLista, true, true, true, true);
            listaReordenavel.drawHeaderCallback += DesenharCabecalho;
            listaReordenavel.drawElementCallback += DesenharElemento;
            listaReordenavel.elementHeightCallback += ObterAlturaElemento;
        }
    }

    private void DesenharCabecalho(Rect retangulo)
    {
        EditorGUI.LabelField(retangulo, "Lista de Pessoas");
    }

    private void DesenharElemento(Rect retangulo, int indice, bool ativo, bool focado)
    {
        var elemento = propriedadeLista.GetArrayElementAtIndex(indice);
        var retanguloDobra = new Rect(retangulo.x, retangulo.y, retangulo.width, EditorGUIUtility.singleLineHeight);

        int nivelIndentacao = EditorGUI.indentLevel;
        EditorGUI.indentLevel = 1;

        elemento.isExpanded = EditorGUI.Foldout(retanguloDobra, elemento.isExpanded, new GUIContent("Pessoa " + indice));

        EditorGUI.indentLevel = nivelIndentacao;

        if (elemento.isExpanded)
        {
            var retanguloConteudo = new Rect(retangulo.x, retangulo.y + retanguloDobra.height, retangulo.width, EditorGUI.GetPropertyHeight(elemento));
            EditorGUI.PropertyField(retanguloConteudo, elemento);
        }
    }

    private float ObterAlturaElemento(int indice)
    {
        var elemento = propriedadeLista.GetArrayElementAtIndex(indice);
        float altura = EditorGUIUtility.singleLineHeight;

        if (elemento.isExpanded)
            altura += EditorGUI.GetPropertyHeight(elemento);

        return altura;
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();
        listaReordenavel.DoLayoutList();
        serializedObject.ApplyModifiedProperties();
    }
}

Tags: Unity C# Inspector ScriptableObject PropertyDrawer

Publicado em 6-25 00:10