2
\$\begingroup\$

How could I make the array size readonly in inspector in Unity with a custom attribute?

Here is my ReadOnly attribute:

using game_editor.drawers;
using UnityEditor;
using UnityEngine;

namespace editor.drawers
{
    [CustomPropertyDrawer(typeof(ReadOnlyAttribute))]
    public class ReadOnlyDrawer : PropertyDrawer
    {
        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
            return EditorGUI.GetPropertyHeight(property, label, true);
        }

        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            GUI.enabled = false;
            EditorGUI.PropertyField(position, property, label, true);
            GUI.enabled = true;
        }
    }
}

    using UnityEngine;
    
    namespace game_editor.drawers
    {
        public class ReadOnlyAttribute : PropertyAttribute
        {
    
        }
    }

Here is how I use it:

public class MainObject : MonoBehaviour
{
    [ReadOnly]
    [SerializeField]
    GameObject[] prefabs;
}

The problem right now is that I still can edit my array size (the MainObject.prefabs array in this case) in editor. How could I modify my ReadOnlyDrawer to prevent that?

I do not know the array length beforehand. So, the OnValidate solution like this one:

private const int SIZE = 5;
 public int[] ints = new int[SIZE];
 
 void OnValidate()
 {
     if (ints.Length != SIZE)
     {
         Debug.LogWarning("Don't change the 'ints' field's array size!");
         Array.Resize(ref ints, SIZE);
     }
 }

(source) won't work in my case.

Also, I want to use this attribute thorughout my project in different places. So, I do not want to create a custom inspector, I just want to utilize the drawing attribute.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I had to figure out how to do this. I am building a custom inspector with UI Toolkit, and this is the code in that context:

[CustomEditor(typeof(MyComponent))]
public class MyComponentInspector : Editor {
    public override VisualElement CreateInspectorGUI() {
        var inspector = new VisualElement();

        var myArray = new PropertyField(
            this.serializedObject.FindProperty("myArray")
        );

        inspector.Add(myArray);

        // Wait for property field to be populated before modifying it.
        // Source: https://forum.unity.com/threads/solved-how-to-force-update-visual-element-on-the-current-frame.727040/#post-4984787
        _ = myArray.schedule.Execute(() => {
            // Get size field of array
            IntegerField sizeField = myArray.Q<IntegerField>();

            // Disallow changing array size in inspector
            sizeField.SetEnabled(false);
        });

        return inspector;
    }
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .