Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
  • Help Room /
avatar image
3
Question by coffiarts · Jan 01, 2019 at 11:44 PM · inspectoreditor-scriptingarrayscustom editorpropertydrawer

How to edit array/list property with custom PropertyDrawer?

This is not about custom inspectors for arrays/lists in general (I assume/hope that I already know how to do that). I am having a specifically weird behaviour only when using arrays/lists as nested properties.

In brief: Using EditorGUI.PropertyField on a SerializedProperty (which is actually a string[]) won't display a proper array/list inspector element. Instead, I am only seeing a dull "foldout icon".

And In details...

I am using a custom PropertyDrawer (see source code below) for handling a simple custom data class instance inside the Inspector.

My approach seems to be very simple, mainly follwowing the Unity docs at: https://docs.unity3d.com/ScriptReference/PropertyDrawer.html

Here's my"data item class":

 [Serializable]
 public class ThesaurusItem
     {
         public string word;
         public string[] syllables;
     }

The issue goes with its "syllables" property (string[]). The data class is used as a plain and straight property inside the surrounding MonoBehaviour class:

     public class Thesaurus : MonoBehaviour
     {
         public ThesaurusItem testItem;
     }

Here's my issue: Any array or list type properties like "syllables" are only displayed as a "foldout" icon - and otherwise emtpy. In particular, there's no "size" input field at all.

This is what I'd expect to see in the Inspector (which is what I get for a simple public string[] class property): alt text

And here's what I actually get: alt text

As soon as my string[] property is handled as part of the data item class by the custom drawer, it is nothing more than a "foldout" icon - with nothing else otherwise. I can click it (i.e. it turns into a downward arrow), but it doesn't expand anything.

Of course my array property is still empty, so I don't expect to see any content. But I would expect to see at least the "size" field.

Finally, here's my PropertyDrawer:

     // Note that this is more or less identical to Unity's example code here: https://docs.unity3d.com/ScriptReference/PropertyDrawer.html
     [CustomPropertyDrawer(typeof(ThesaurusItem))]
     public class ThesaurusItemDrawer : PropertyDrawer
     {
         // Draw the property inside the given rect
         public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
         {
             // Using BeginProperty / EndProperty on the parent property means that
             // prefab override logic works on the entire property.
             EditorGUI.BeginProperty(position, label, property);
 
             // Draw label
             position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
 
             // Don't make child fields be indented
             var indent = EditorGUI.indentLevel;
             EditorGUI.indentLevel = 0;
 
             // Calculate rects
             Rect wordRect = new Rectposition.x, position.y, 90, position.height);
             Rect syllablesRect = new Rect(wordRect.position.x + wordRect.width + 20, position.y, 50, position.height);
 
             // Draw fields - pass GUIContent.none to each so they are drawn without labels
             EditorGUI.PropertyField(wordRect, property.FindPropertyRelative("word"), GUIContent.none);
             EditorGUI.PropertyField(syllablesRect, property.FindPropertyRelative("syllables"), GUIContent.none, true);
 
             // Set indent back to what it was
             EditorGUI.indentLevel = indent;
 
             EditorGUI.EndProperty();
         }
     }
     

Any ideas what's going wrong here?

propertydrawer-arrays-03.png (6.2 kB)
propertydrawer-arrays-01.png (5.2 kB)
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

3 Replies

· Add your reply
  • Sort: 
avatar image
3

Answer by coffiarts · Jan 04, 2019 at 08:38 AM

I've found a workaround for my own (admittedly quite lenghty and complicated) question, so I'd like to share it myself.

First of all: Unity doesn't seem to support custom drawers for arrays and lists themselves. See this older post from a Unity staff member Literally:

You can't make a PropertyDrawer for arrays or generic lists themselves. [...] On the plus side, elements inside arrays and lists do work with PropertyDrawers.

The solution sounds simple: Wrapping arrays/lists in a parent class and creating a drawer for the parent.

This works fine (in terms that the drawer will actually be applied to the array/list). The downside is that the individual elements of the array/list won't be automatically rendered, neither the "size" field. You still have to implement this manually (by looping etc.). Especially the handling of the array size looks a bit nasty, as you need to track the size in a separate int property (see "arrSize" below) and listen to changes to it.

My solution looks like this now:

Custom Wrapper class plus Drawer for a plain string[] property:

 // Encapsulation of a plain string[] inside a Property, so that it can be used together with a custom PropertyDrawer (StringArrayAttributeDrawer)
     [Serializable]
     public class StringArrayEditorAttribute : PropertyAttribute
     {
         public static readonly int INITIAL_SIZE = 1;
         public string[] values;
 
         public StringArrayEditorAttribute()
         {
             values = new string[INITIAL_SIZE];
             for (int i = 0; i < INITIAL_SIZE; i++)
             {
                 values[i] = "";
             }
         }
     }

 [CustomPropertyDrawer(typeof(StringArrayEditorAttribute))]
 public class StringArrayEditorAttributeDrawer : PropertyDrawer
 {

     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
     {
         SerializedProperty arrayProp = property.FindPropertyRelative("values");
         for (int i = 0; i < arrayProp.arraySize; i++)
         {
              // This will display an Inspector Field for each array item (layout this as desired)
             SerializedProperty value = arrayProp.GetArrayElementAtIndex(i);
             EditorGUI.PropertyField(position, value, GUIContent.none);
         }
     }
 }

Use this property inside your surrounding class instead of a string[]:

    [Serializable]
     public class MyListItem : PropertyAttribute
     {
         public StringArrayEditorAttribute stringArrProp =  new StringArrayEditorAttribute();
         public int arrSize; // necessary for handling changes to the array's size!
     }

Inside the Drawer for the surrounding class, it's sufficient to pass the property into a regular PropertyField

  [CustomPropertyDrawer(typeof(ThesaurusItem))]
  public class ThesaurusItemDrawer : PropertyDrawer
  {
             [...]
             EditorGUI.LabelField(someRect, new GUIContent("size"));
             [...]
             EditorGUI.PropertyField(someRect, property.FindPropertyRelative("arrSize"), GUIContent.none);
              [...]
             EditorGUI.PropertyField(someRect, property.FindPropertyRelative("stringArrProp"), GUIContent.none);
 }
 

Now for the ugly part: Keeping track of array size changes...

I found no better way for this than using OnValidate() in the surrounding (i.e. the inspected) MonoBehaviour component (credits to user Edy for his solution proposed here): whenever anything changes in the inspector, we need to check any of the array items for a change in arrSize, and then adjust the array length accordingly (very nasty, but it works!):

 public class MyComponent : MonoBehaviour
 {
     OnValidate()
     {
             foreach (MyListItem item in someParentList)
             {
                 // Do we need to adjust the array to a new size?
                 if (item.arrSize != item.stringArrProp.values.Length)
                 {
                     string[] newArray = new string[item.arrSize];
                     for (int i = 0; i < newArray.Length; i++)
                     {
                         if (item.stringArrProp.values.Length > i)
                         {
                             newArray[i] = item.stringArrProp.values[i];
                         }
                         else
                         {
                             newArray[i] = "";
                         }
                     }
                     item.stringArrProp.values = newArray;
                 }
     }
     }
 }


Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by ShawnFeatherly · Aug 15, 2019 at 12:26 AM

Similar to @coffiarts 's answer, here's a pretty clean example of wrapping an array type, such as string[], in another class. https://github.com/cfoulston/Unity-Reorderable-List/blob/master/Example/Example.cs From what I can tell, he found a way around the array size check requirement being in OnValidate().

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by tomekkie · Aug 04, 2021 at 06:17 AM

Looks like this is not a problem in the recent versions of Unity any more. I have run into this issue after importing the CustomPropertyDrawer from 2020.2.2f1 - where it is working properly on lists or arrays without any custom wrapper - to 2020.1.0f1 - where it is not working.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

183 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Popup to choose which child class I want in Custom Editor Inspector 0 Answers

Property Drawer ArgumentException 1 Answer

Is there a way to live-update script-controlled UI formatting in the editor? 0 Answers

Displaying recursive types in inspector (Custom Editor) 0 Answers

Custom Inspector for Particle System 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges