I’m trying to implement a drawer for an array type. The closest I can get is by writing a property drawer for the elements it contains, but not for the array (parent).
[CustomPropertyDrawer (typeof (PutOnArraysAttribute))]
// I'll get OnGUI calls for the elements of the array but not for the array itself
Create a small System.Serializable nested struct/class within your MonoBehaviour to contain your list:
public class SomeMonoBehaviour : MonoBehaviour
{
[Serializable] public struct ThingsWrapper {
public List<string> list;
// optional, for convenience (so you can use ThingsWrapper as if it's a List):
public static implicit operator List<string>(ThingsWrapper c) { return c.list; }
public static implicit operator ThingsWrapper(List<string> l) { return new PointsWrapper(){ list = l }; }
}
…
Add a field to your MonoBehaviour of this nested ThingsWrapper type adorned with your PutOnArrays attribute:
…
[PutOnArrays]
public ThingsWrapper things;
…
(Those implicit operators allows your code to keep using the field as if it were an array/list:)
…
void Awake() {
List<string> things = this.things;
things.Add("hi");
Debug.Log(things);
}
…
} // end of SomeMonoBehaviour
Then, in your PutOnArraysDrawer class, use FindPropertyRelative() to work with the list field:
[CustomPropertyDrawer(typeof(PutOnArraysAttribute))]
public class PutOnArraysDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
property = property.FindPropertyRelative("list");
// …
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
property = property.FindPropertyRelative("list");
// …
}
}
This approach both allows you specify custom attribute/drawers for arrays and for their elements, and keeps those attribute associations within your MonoBehaviour (rather than requiring new class files for each use-case).
If you wanted, I’m sure you wrap up ThingsWrapper into a reusable base class to simplify the code in your class— but it’s really not that much code in the first place. I’ve set up my Attribute to take a listFieldName constructor arg and store it in a property, then my Drawer passes ((PutOnArraysAttribute)this.attribute).listFieldName into FindPropertyRelative() (instead of assuming "list"). Where you go with this is up to you.
I believe you cannot create a PropertyDrawer for an Array, only an Editor for the containing class and then PropertyDrawers for the members (like you mentioned).