It is not possible to gray out the entire list without writing a custom editor window. In the Unity source code, you can see that attributes are never applied to arrays.
In PropertyHandler.cs
within the method HandleDrawnType
, beginning on line 102:
// Use PropertyDrawer on array elements, not on array itself.
// If there's a PropertyAttribute on an array, we want to apply it to the individual array elements instead.
// This is the only convenient way we can let the user apply PropertyDrawer attributes to elements inside an array.
if (propertyType != null && propertyType.IsArrayOrList())
return;
The class used internally to display lists is UnityEditorInternal.ReorderableList
. This article shows how it can be customized. We can use this to force fields marked with our custom attribute to be grayed out. Here is my attempt, written for any Unity object:
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
using System;
using System.Reflection;
using System.Collections.Generic;
[CustomEditor(typeof(UnityEngine.Object), true), CanEditMultipleObjects]
public class FullyDisabledListEditor : Editor
{
Dictionary<string, ReorderableList> _disabledLists;
private void OnEnable()
{
if(_disabledLists == null) _disabledLists = new();
var fields = serializedObject.targetObject.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
foreach(FieldInfo field in fields)
{
if(!IsArrayOrList(field.FieldType)) continue;
IEnumerator<CustomAttributeData> attributes = field.CustomAttributes.GetEnumerator();
while (attributes.MoveNext())
{
if(attributes.Current.AttributeType != typeof(NotEditableAttribute)) continue;
CreateDisabledList(field.Name);
}
}
}
private bool IsArrayOrList(Type listType)
{
if (listType.IsArray)
return true;
else if (listType.IsGenericType && listType.GetGenericTypeDefinition() == typeof(List<>))
return true;
return false;
}
private void CreateDisabledList(string fieldName)
{
var listProperty = serializedObject.FindProperty(fieldName);
var list = new ReorderableList(
serializedObject,
listProperty,
false, //this setting allows you to rearrange the items
true, //this setting displays a header label
false, //this setting removes the 'add elements' button
false //this setting removes the 'remove elements' button
);
list.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
{
var property = list.serializedProperty.GetArrayElementAtIndex(index);
rect.y += 2; //for some reason fields are vertically off center by default
EditorGUI.PropertyField(rect, property);
};
list.drawHeaderCallback = (Rect rect) => {
EditorGUI.LabelField(rect, listProperty.displayName);
};
_disabledLists.Add(fieldName, list);
}
public override void OnInspectorGUI()
{
serializedObject.Update();
SerializedProperty property = serializedObject.GetIterator();
while (property.NextVisible(true))
HandlePropertyDisplay(property);
serializedObject.ApplyModifiedProperties();
}
private void HandlePropertyDisplay(SerializedProperty property)
{
//skip redrawing child properties
if(property.propertyPath.Contains('.', StringComparison.Ordinal)) return;
//gray out the script, as it normally is
if(property.propertyPath.Equals("m_Script", StringComparison.Ordinal))
{
ShowDisabledProperty(property);
return;
}
//gray out the arrays we marked
if(_disabledLists.ContainsKey(property.name))
{
_disabledLists[property.name].DoLayoutList();
return;
}
//everything else is shown normally (non-array fields will be grayed out by the attribute drawer)
EditorGUILayout.PropertyField(property);
}
private void ShowDisabledProperty(SerializedProperty property)
{
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.PropertyField(property, true);
EditorGUI.EndDisabledGroup();
}
}
Unfortunately, I couldn't use the attribute written by ChoopTwisk in their answer. I didn't figure out a way to check the result of the conditions from within the editor class. In my example, any field marked with [NotEditable]
will be permanently grayed out. If you want to use that, the code for it is below. I found it here.
using UnityEditor;
using UnityEngine;
public class NotEditableAttribute : PropertyAttribute { }
[CustomPropertyDrawer(typeof(NotEditableAttribute))]
public sealed class NotEditableDrawer : 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)
{
EditorGUI.BeginDisabledGroup(true);
EditorGUI.PropertyField(position, property, label, true);
EditorGUI.EndDisabledGroup();
}
}