• 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 /
avatar image
38
Question by lpp · Jul 09, 2013 at 09:21 PM · inspectorproperty fieldsread-only

How to make a readonly property in inspector?

I tried t$$anonymous$$s approach:

 private var _worldVelocity : Vector3;
 public function get worldVelocity () : Vector3 { return _worldVelocity; }
 private function set worldVelocity (value : Vector3) { _worldVelocity = value;


but it hasn't worked at all in the inspector.

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

9 Replies

· Add your reply
  • Sort: 
avatar image
128

Answer by It3ration · Oct 01, 2014 at 05:37 PM

T$$anonymous$$s is the end-all answer - it will allow you to mark -any- field as readonly with a single property attribute / property drawer. It's partially based on scottmontgomerie's answer. T$$anonymous$$s version also dispatches the property height based on how "expanded" the property is.

 public class ReadOnlyAttribute : PropertyAttribute
 {
 
 }
 
 [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;
     }
 }
 
 public class Test
 {
     [ReadOnly] public string a;
     [ReadOnly] public int b;
     [ReadOnly] public Material c;
     [ReadOnly] public List<int> d = new List<int>();
 }

Works like a charm.

Comment
Add comment · Show 21 · 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 Lev-Lukomskyi · Oct 02, 2014 at 12:11 PM 4
Share

Just tried this code - works great:

alt text

And you dont need to override GetPropertyHeight - just remove it and code will be simpler.

showonlypropertydrawer.png (8.5 kB)
avatar image QuantumHive · Dec 26, 2014 at 09:53 PM 2
Share

Why setting GUI.enabled = true; after setting it to false?

avatar image ismakefire QuantumHive · Jun 07, 2017 at 12:27 AM 2
Share

I've worked this before and if you exit the method with GUI.enabled set to false the entire element will be ignored, while if GUI.enabled is false while populating children they will appear disabled.

avatar image Ben-BearFish · Mar 25, 2015 at 10:54 PM 1
Share

Did anyone manage to get this to work in Unity 4.6 and 5?

avatar image Bearabeck · Mar 31, 2015 at 03:48 PM 8
Share

@Ben BearFish put ReadonlyAttribute in its own script in a folder outside of the Editor folder, make sure ReadOnlyDrawer is in the Editor folder.

avatar image The-Little-Guy · Dec 27, 2015 at 06:36 PM 1
Share

For anyone doing this on a private/protected field, you need to also serialize the field:

 [ReadOnlyAttribute, SerializeField] private float health;
Show more comments
avatar image
46

Answer by Lev-Lukomskyi · Sep 19, 2014 at 07:30 PM

Use t$$anonymous$$s:

Assets/Scripts/ShowOnlyAttribute.cs:

 using UnityEngine;
 
 public class ShowOnlyAttribute : PropertyAttribute
 {
 }

Assets/Editor/ShowOnlyDrawer:

 using UnityEditor;
 using UnityEngine;
 
 [CustomPropertyDrawer(typeof(ShowOnlyAttribute))]
 public class ShowOnlyDrawer : PropertyDrawer
 {
     public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
     {
         string valueStr;
 
         switch (prop.propertyType)
         {
             case SerializedPropertyType.Integer:
                 valueStr = prop.intValue.ToString();
                 break;
             case SerializedPropertyType.Boolean:
                 valueStr = prop.boolValue.ToString();
                 break;
             case SerializedPropertyType.Float:
                 valueStr = prop.floatValue.ToString("0.00000");
                 break;
             case SerializedPropertyType.String:
                 valueStr = prop.stringValue;
                 break;
             default:
                 valueStr = "(not supported)";
                 break;
         }
 
         EditorGUI.LabelField(position,label.text, valueStr);
     }
 }

Use in your object:

 public class MyClass : MonoBehaviour
 {
     [ShowOnly] public float aaa = 123.45678f;
     [ShowOnly] public int bbb = 234;
     [ShowOnly] public bool ccc = false;
     [ShowOnly] [SerializeField] bool ddd = true;
 }

You will get t$$anonymous$$s:

alt text


showonlyscreenshot.png (8.5 kB)
Comment
Add comment · Show 6 · 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 HewwittHD · Aug 08, 2019 at 10:46 PM 2
Share

This worked for me, thanks!

It only works for ints, bools, floats, and strings tho. If anyone needs this code for enumerators, insert these lines into "ShowOnlyDrawer.cs", just before "default:":

 case SerializedPropertyType.Enum:
     valueStr = prop.enumNames[prop.enumValueIndex];
     break;
avatar image Migmac · Oct 15, 2019 at 06:47 AM 2
Share

This worked for me but I wanted to use this to also have GameObjects [ShowOnly].

So after several hours of trying different things and reading documentation, this is what I came up with:

 case SerializedPropertyType.ObjectReference:
     try {
         valueStr = prop.objectReferenceValue.ToString ();
     } catch (NullReferenceException) {
         valueStr = "None (Game Object)";
     }
     break;

Hope this helps someone.

avatar image DSivtsov · Nov 13, 2020 at 06:25 PM 1
Share

This worked for me, thanks! Add for Enum

         case SerializedPropertyType.Enum:
             valueStr = prop.enumDisplayNames[prop.enumValueIndex];
             break;

avatar image mannyhams · Jan 23, 2021 at 03:55 AM 0
Share

Works very nicely for me as well in Unity 2019.4.13f1, thanks for this!

Note that many other value types are possible in SerializedProperty (the prop param in ShowOnlyDrawer#OnGUI).

avatar image Lashes · Oct 28, 2021 at 01:41 PM 0
Share

This did help - thank you! I also had to add using: System; to my class to use the 'NullReferenceException', so VisualStudio didn't yell at me. :)

But this is a nice and simple solution that gives you a lot of flexibility over display per type. Thanks!

Show more comments
avatar image
9

Answer by FuzzyLogic · Mar 07, 2018 at 11:10 AM

The solution posted by @It3ration does not work with fields that already have a CustomPropertyDrawer.

.

Using the ReadOnly attribute will cause the field to be displayed with the default property drawer instead of the custom property drawer.

.

T$$anonymous$$s solution expands on the solution by @It3ration to add 2 new attributes ( BeginReadOnlyAttribute and EndReadOnlyAttribute ) so that any fields in between the two attribute tags will be read-only. Using t$$anonymous$$s method will allow CustomPropertyDrawers to work. The important part is that the new attributes use DecoratorDrawers instead of a PropertyDrawer.

.

For convenience, the ReadOnlyAttribute is also implemented but will only work for a single field with a default property drawer.

.

ReadOnlyAttribute.cs (MUST NOT be in Editor folder)

 Using UnityEngine;
 
 /// <summary>
 /// Display a field as read-only in the inspector.
 /// CustomPropertyDrawers will not work when t$$anonymous$$s attribute is used.
 /// </summary>
 /// <seealso cref="BeginReadOnlyGroupAttribute"/>
 /// <seealso cref="EndReadOnlyGroupAttribute"/>
 public class ReadOnlyAttribute : PropertyAttribute { }
 
 /// <summary>
 /// Display one or more fields as read-only in the inspector.
 /// Use <see cref="EndReadOnlyGroupAttribute"/> to close the group.
 /// Works with CustomPropertyDrawers.
 /// </summary>
 /// <seealso cref="EndReadOnlyGroupAttribute"/>
 /// <seealso cref="ReadOnlyAttribute"/>
 public class BeginReadOnlyGroupAttribute : PropertyAttribute { }
 
 /// <summary>
 /// Use with <see cref="BeginReadOnlyGroupAttribute"/>.
 /// Close the read-only group and resume editable fields.
 /// </summary>
 /// <seealso cref="BeginReadOnlyGroupAttribute"/>
 /// <seealso cref="ReadOnlyAttribute"/>
 public class EndReadOnlyGroupAttribute : PropertyAttribute { }


ReadOnlyDrawer.cs (MUST be in Editor folder)

 using UnityEditor;
 using UnityEngine;
 
 [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 ) {
         using (var scope = new EditorGUI.DisabledGroupScope(true)) {
             EditorGUI.PropertyField( position, property, label, true );
         }
     }
 
 }
 
 [CustomPropertyDrawer( typeof( BeginReadOnlyGroupAttribute ) )]
 public class BeginReadOnlyGroupDrawer : DecoratorDrawer {
 
     public override float GetHeight() { return 0; }
 
     public override void OnGUI( Rect position ) {
         EditorGUI.BeginDisabledGroup( true );
     }
 
 }
 
 [CustomPropertyDrawer( typeof( EndReadOnlyGroupAttribute ) )]
 public class EndReadOnlyGroupDrawer : DecoratorDrawer {
 
     public override float GetHeight() { return 0; }
 
     public override void OnGUI( Rect position ) {
         EditorGUI.EndDisabledGroup();
     }
 
 }


Example.cs

 using UnityEngine;
 
 public class ReadOnlyExample : MonoBehaviour {
     [BeginReadOnlyGroup] // tag a group of fields as ReadOnly
     public string a;
     public int b;
     public Material c;
     public List<int> d = new List<int>();
     public CustomTypeWithPropertyDrawer e; // Works!
     [EndReadOnlyGroup]

     [ReadOnly] public string a2;
     [ReadOnly] public CustomTypeWithPropertyDrawer e2; // DOES NOT USE CustomPropertyDrawer!

     [BeginReadOnlyGroup]
     public int b2;
     public Material c2;
     public List<int> d2 = new List<int>();
     // Attribute tags apply to the next field of w$$anonymous$$ch there are no more so Unity/C# complains.
     // Since there are no more fields, we can omit the closing tag.
     // [EndReadOnlyGroup]
   
 }
Comment
Add comment · Show 4 · 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 JPoenisch · Mar 20, 2018 at 10:46 AM 0
Share

I just tested your solution: It does not work unfortunately.


I cannot add screenshots (since reputation system I guess) but:


ReadOnlyAttribute.cs is NOT in Editor
ReadOnlyDrawer IS in Editor


My Example.cs

 using System;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class Examples : MonoBehaviour
 {
     [ReadOnly]
     [SerializeField]
     private Vector3 vector3;
     
     [ReadOnly, SerializeField]
     private List<SerializableClass> serializableClassListReadOnly = new List<SerializableClass>()
     {
         new SerializableClass("Test1", 1),
         new SerializableClass("Test2", 2),
         new SerializableClass("Test3", 3),
         new SerializableClass("Test4", 4)
     };
 
     [ReadOnly, SerializeField]
     private List<int> intListReadOnly = new List<int>() { 1, 2, 3, 4 };
 
     [BeginReadOnlyGroup]
     [SerializeField]
     private List<SerializableClass> serializableClassListReadOnlyGroup = new List<SerializableClass>() {
         new SerializableClass("Test1", 1),
         new SerializableClass("Test2", 2),
         new SerializableClass("Test3", 3),
         new SerializableClass("Test4", 4)
     };
 
     [SerializeField] private List<int> intListReadOnlyGroup = new List<int>() { 1, 2, 3, 4 };
 
     // Since there are no more fields, we can omit the closing tag.
     [EndReadOnlyGroup]
     [ReadOnly]
     [SerializeField]
     private Quaternion quaternion;
 
     [Serializable]
     public class SerializableClass
     {
         public string Name;
         public int Value;
 
         public SerializableClass(string name, int value)
         {
             Name = name;
             Value = value;
         }
     }
 }


In the Inspector all Variables with [ReadOnly] just do the same as It3ration's solution. On List still the name and size are not disabled.


On the lists within the [BeginReadOnlyGroup] and [EndReadOnlyGroup] on the name/foldout of the first list is disabled, all the other values are not.

(I just placed another value below the group to see if it makes a differents if the ending attribute is not omitted.)

avatar image FuzzyLogic JPoenisch · Mar 20, 2018 at 06:33 PM 0
Share

This solution only addresses creating readonly fields where the field is a type that already has its own CustomPropertyDrawer.

Unfortunately, I don't think there is any simple way to create readonly lists. The ReadOnlyGroup attribute will behave the same as the ReadOnly attribute in this case.

Unity only applies the attribute to the first element of a list. I think you would need to create a property drawer for the elements themselves that specifically handles disabling those fields.

In the case of the List<SeriablizableClass>, I think you can apply the ReadOnly (or ReadOnlyGroup) attribute to the name and value fields within your SerializableClass.

For the List<int>, it's much trickier. You would have to create your own int type and then create a CustomPropertyDrawer for that type.

The other option is to create a custom list type, which I don't think you want to do either. It gets to the point where you might as well just make a custom inspector.

avatar image jethrogillgren · May 17, 2018 at 10:17 AM 0
Share

Should be accepted answer, Works Great, thanks!
Useful in conjunction with [SerializeField] to expose private/protected values.

avatar image huulong · Mar 12, 2021 at 11:34 PM 0
Share

Duplicating my comment on the other answer, but new EditorGUI.DisabledScope(true) is now recommended over DisabledGroupScope as it's a struct instead of a class and offers a slight advantage on memory usage. Otherwise, works fine! (I only tested the first version for members without custom property drawers)

avatar image
4

Answer by Coderdood · Jul 09, 2013 at 09:59 PM

Simple way is to use the Inspector in Debug Mode. Instructions / details are located in the documentation.

Otherwise you may look at creating a custom editor. Documentation here.

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
2

Answer by scottmontgomerie · Jul 24, 2014 at 08:43 PM

From http://buildoutput.blogspot.com/2014/01/the-visual-connect-that-unitys.html

It's not a great solution because of all the #ifdef UNITY_EDITOR lines, but it works and I'm sure with some refinement it could be useful.

ReadOnlyPropertyAttribute.cs:

 using System;
 using UnityEngine;
 #if UNITY_EDITOR
 using UnityEditor;
 #endif
 public abstract class ReadOnlyPropertyAttribute : PropertyAttribute
 {
     public string Displayname { get; private set; }
     public ReadOnlyPropertyAttribute( string displayName )
     {
         t$$anonymous$$s.Displayname = displayName;
     }
 }
  
 public class ReadOnlyObjectAttribute : ReadOnlyPropertyAttribute
 {
     public ReadOnlyObjectAttribute( string displayName ) : base( displayName )
     {
     }
 }
  
 public class ReadOnlyVector3Attribute : ReadOnlyPropertyAttribute
 {
     public ReadOnlyVector3Attribute( string displayName ) : base( displayName )
     {
     }
 }
 

PropertyDrawer.cs:

 using System;
 using UnityEngine;
 #if UNITY_EDITOR
 using UnityEditor;
 #endif

 #if UNITY_EDITOR
 [ CustomPropertyDrawer( typeof( ReadOnlyObjectAttribute ) ) ]
 public class ReadOnlyObjectDrawer : PropertyDrawer
 {
     public override void OnGUI( Rect position, SerializedProperty prop, GUIContent label )
     {
         EditorGUI.ObjectField( position, ( attribute as ReadOnlyPropertyAttribute ).Displayname + " (Read Only)", prop.objectReferenceValue, typeof( System.Object ), true );
     }
 }
  
 [ CustomPropertyDrawer( typeof( ReadOnlyVector3Attribute ) ) ]
 public class ReadOnlyVector3Drawer : PropertyDrawer
 {
     public override void OnGUI( Rect position, SerializedProperty prop, GUIContent label )
     {
     GUI.enabled = false;
     EditorGUI.Vector3Field( position, ( attribute as ReadOnlyPropertyAttribute ).Displayname + " (Read Only)", prop.vector3Value );
     GUI.enabled = true;
     }
     
     public override float GetPropertyHeight( SerializedProperty property, GUIContent label )
     {
         return base.GetPropertyHeight( property, label ) * 2.0f;
     }
 }
 #endif

Then you can do t$$anonymous$$s in your classes:

 #if UNITY_EDITOR
 [ SerializeField ][ ReadOnlyObjectAttribute( "DoF Material" ) ]
 #endif
  private Material m_material;





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
  • 1
  • 2
  • ›

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.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

50 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

Related Questions

Inspector->Texture: Can't effectively change properties (tiling/offset) 0 Answers

EditorGUILayout.PropertyField cannot draw custom class? 2 Answers

How to make public variable read-only during run-time? 3 Answers

Unity editor not saving object changes 4 Answers

How to display computed getter in inspector? 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