- Home /
Hide/Show properties dynamically in inspector.
Here's the thing.
How do I hide/show items in the inspector tab dinamically, like iTween? When I select 'MoveBy', it loads all the properties available to the 'MoveBy' function. When I change it to something else, it unloads the properties (hides them from the inspector), and shows the properties available to the newly selected function.
I'm doing something like that, but I'm completely lost. I've read the 'Extending the Editor' section, and tried [ExecuteInEditMode], but I just don't know how to change the property display status on the Update() function.
Answer by luizgpa · Dec 07, 2011 at 09:04 PM
You need to create a Custom Editor for your script. Then you show the fields based on the internal state of the object being edit. Eg:
public class MyScript : MonoBehaviour
{
public bool flag;
public int i = 1;
}
[CustomEditor(typeof(MyScript))]
public class MyScriptEditor : Editor
{
void OnInspectorGUI()
{
var myScript = target as MyScript;
myScript.flag = GUILayout.Toggle(myScript.flag, "Flag");
if(myScript.flag)
myScript.i = EditorGUILayout.IntSlider("I field:", myScript.i , 1 , 100);
}
}
In the example the Inspector will show a slider only if flag is set to true.
var myScript = target as $$anonymous$$yScript;
↑ This line helps me a lot! Thanks man :D I'm a new guy in Custom Editor and I'm learning this with the basic tutorial on the official website. But somehow it told us to use "target.variable" directly and it doesn't work anyway until I add the line in your script.
the answer should be edited, it works only if Campusanis answer is also considered. just add:
override public void OnInspectorGUI()
Answer by Deadcow_ · Mar 16, 2018 at 06:07 AM
I know it's super necro post but I've got cool attribute to share. It allows to conditionally display field inspector based on some other values, like values of other fields.
public bool WanderAround;
[ConditionalField("WanderAround")] public float WanderDistance = 5;
public AIState NextState = AIState.None;
[ConditionalField("NextState", AIState.Idle)] public float IdleTime = 5;
I love this approach, but I think you are using some custom extensions that aren't included in your code. In ConditionalFieldAttributeDrawer.cs I had to rewrite PropertyToCheck.IsNullOrEmpty() as string.IsNullOrEmpty(PropertyToCheck) and had to extract the enum name from the SerializedProperty manually (I assume AsStringValue() is an extension method.)
Yep, it's true. This attribute is part of my library. There is more lovely stuff there, although most of it is not documented
Could you share how you extracted the enum name? I went with:
if (conditionProperty.propertyType == SerializedPropertyType.Enum) {
int index = conditionProperty.enumValueIndex;
conditionPropertyStringValue = conditionProperty.enumDisplayNames[index].ToUpper();
}
Yep, I do the same. There is my extension method for Serialized Properties:
/// <summary>
/// Get string representation of serialized property, even for non-string fields
/// </summary>
public static string AsStringValue(this SerializedProperty property)
{
switch (property.propertyType)
{
case SerializedPropertyType.String:
return property.stringValue;
case SerializedPropertyType.Character:
case SerializedPropertyType.Integer:
if (property.type == "char") return System.Convert.ToChar(property.intValue).ToString();
return property.intValue.ToString();
case SerializedPropertyType.ObjectReference:
return property.objectReferenceValue != null ? property.objectReferenceValue.ToString() : "null";
case SerializedPropertyType.Boolean:
return property.boolValue.ToString();
case SerializedPropertyType.Enum:
return property.enumNames[property.enumValueIndex];
default:
return string.Empty;
}
}
Thanks for that great extension! It is really easy to use but i am having problems with array properties. I have only added "ConditionalFieldAttribute.cs" and "ConditionalFieldAttributeDrawer.cs" scripts to my project. When i add a ConditionalField attribute to an array, it doesn't hide the properties in the inspector. I am using 2017.4.1f1 edition of unity and i couldn't get it to working. Thanks!
Yey. Like, 14 days ago I fixed this issue. Check my latest commit and this method specifically
I am indeed using the latest version. I've added two images below to show what i did.
Is there something that i am doing wrong? I've put your "ConditionalFieldAttribute.cs" in Assets folder and "ConditionalFieldAttributeDrawer.cs" file to Assets/Editor folder. It works with normal fields but it doesn't hide arrays. Thanks for the help!
This sounds and looks super convenient. However when I pasted this two scripts into my poject, I get the following errors:
ConditionalFieldAttributeDrawer.cs(9,49): error CS1644: Feature `expression bodied members' cannot be used because it is not part of the C# 4.0 language specification
ConditionalFieldAttributeDrawer.cs(11,36): error CS1644: Feature `expression bodied members' cannot be used because it is not part of the C# 4.0 language specification
ConditionalFieldAttributeDrawer.cs(13,33): error CS1644: Feature `expression bodied members' cannot be used because it is not part of the C# 4.0 language specification
ConditionalFieldAttributeDrawer.cs(33,57): error CS1644: Feature `null propagating operator' cannot be used because it is not part of the C# 4.0 language specification
Visual Studio says these are not available in C# 4 and that I should use language version 6 or greater. Any ideas?
You need to enable C#6 compatibility in Unity
In the Unity editor, go to Edit->Project Settings->Player Set the "Api Compatibility Level" to .NET 4.6
Hey sorry to necro but I guess it's in the same spirit hahah. I'm trying to use this, it's really nice but I'm having one problem, I'm trying to get it to hide Enums as well but this code is a bit beyond me. Do you have any idea how that would be done? Thanks in advance
Would it be possible to do something like:
public bool InstantiateLevelPrefab;
[ConditionalField("InstantiateLevelPrefab",true)]
public int StartFromLevel = 0;
[ConditionalField("InstantiateLevelPrefab", false)]
public GameObject PrefabLevelToDebug;
Like if`InstantiateLevelPrefab`is true show option 1 and if it is false to show option 2.
Right, it worked after updating version. thanks.
Answer by DarthKarki · Jan 11, 2017 at 08:52 PM
The Inspector can be customized by creating a Custom Editor for your script. In your Custom Editor you can then disable fields using EditorGUI.DisabledScope, or hide them completely using FadeGroupScope.
Creating a Custom Editor
First I create my actual game script:
using UnityEngine;
public class MyScript : MonoBehaviour
{
public bool hideBool;
public bool disableBool;
public string someString;
public Color someColor = Color.white;
public int someNumber = 0;
}
To create our Custom Editor, we create another script with the exact same name, with "Editor" appended to the end. Open and initialize the Editor script:
using UnityEngine;
using UnityEditor;
using System;
[CustomEditor(typeof(MyScript))]
public class MyScriptEditor : Editor
{
override public void OnInspectorGUI()
{
}
}
It will need to be using UnityEditor, and the class (MyScriptEditor) has to derive from Editor (as opposed to the default MonoBehaviour). The CustomEditor attribute informs Unity which component it should act as an editor for. In this case, it is the script MyScript.
Since we want to replace what displays by default in the Inspector, we add the function override public void OnInspectorGUI(). If we look at the Inspector for our game object now we can see that it is completely blank and we can set it up from scratch exactly how we want.
Hiding and disabling fields
Here is an example showing both disabling and hiding fields. I will explain what it is doing below:
using UnityEngine;
using UnityEditor;
using System;
[CustomEditor(typeof(MyScript))]
public class MyScriptEditor : Editor
{
override public void OnInspectorGUI()
{
var myScript = target as MyScript;
myScript.hideBool = EditorGUILayout.Toggle("Hide Fields", myScript.hideBool);
using (var group = new EditorGUILayout.FadeGroupScope(Convert.ToSingle(myScript.hideBool)))
{
if (group.visible == false)
{
EditorGUI.indentLevel++;
EditorGUILayout.PrefixLabel("Color");
myScript.someColor = EditorGUILayout.ColorField(myScript.someColor);
EditorGUILayout.PrefixLabel("Text");
myScript.someString = EditorGUILayout.TextField(myScript.someString);
EditorGUILayout.PrefixLabel("Number");
myScript.someNumber = EditorGUILayout.IntSlider(myScript.someNumber, 0, 10);
EditorGUI.indentLevel--;
}
}
myScript.disableBool = GUILayout.Toggle(myScript.disableBool, "Disable Fields");
using (new EditorGUI.DisabledScope(myScript.disableBool))
{
myScript.someColor = EditorGUILayout.ColorField("Color", myScript.someColor);
myScript.someString = EditorGUILayout.TextField("Text", myScript.someString);
myScript.someNumber = EditorGUILayout.IntField("Number", myScript.someNumber);
}
}
}
First we target our script. Then we decide which fields from that script to display, and how.
The first field I display is hideBool, using EditorGUILayout.Toggle. This creates a toggle that displays similarly to how the Inspector shows a bool field by default.
Next I will create a group of fields that I can hide depending on the value of hideBool using FadeGroupScope. The example of this function in the Unity scripting reference shows it being used with an AnimBool to animate the opening and closing, however the Paint() method does not work in their example and I didn't feel like figuring that out as I don't actually want an animation, I simply want the fields to instantly appear or disappear. The reason this is important is the FadeGroupScope is expecting a float value between 0 and 1 to be passed in to determine exactly how open or closed it should be, as opposed to a bool. I used Convert.ToSingle() to convert my bool to a 0 or 1.
Inside this function are some examples of ways you can display your fields which I pulled from the script reference.
After all of this, I display my disableBool using GUILayout.Toggle. This is another way of displaying a toggle with some different options, which by default shows the checkbox on the left.
Next we set up the DisabledScope, which is simply passed a bool and will disable and grey out any fields inside of it.
This is how it looks once done:
Options unchecked:
Options checked:
Wow, that was one seriously nice answer.
Not only did I learn thanks to your explanation the basics of creating a custom inspector, but you also made me look up the using keyword
Yeah this is one of those answers that restores my faith in humanity haha
Answer by Campusanis · Dec 04, 2015 at 10:47 AM
Since you're overriding a public method ( OnInspectorGUI() ) of the Editor class, the signature of the overriding method should look like
override public void OnInspectorGUI()
Answer by misher · May 07, 2018 at 11:24 AM
Why do you bother with hidin and showing. Split your behaviours into separate components, you will have these components ready for editing in the inspector, your main behaviour will just switch these additional components (they might derive from same base class, or you can use interface)
According to the selected enum value, i am changing the logic of the script. Different properties will be used with different enum values. Interface makes sense but sadly doesn't applicable in my case. It is just for ease of use for the user. I will just hide the properties that user won't use.
That is exactly what i tryed to explain, different properties/values/behaviour should go to different classes, try to look from OOP and unity's components point of view, in other words: use composition whenever you can
Your answer
Follow this Question
Related Questions
setting the properties in the inspector 1 Answer
Showing properties from a base class in inspector? 0 Answers
Making a minor change to Default inspector? 1 Answer
Are inspector values supposed to override [HideInInspector] code? 1 Answer
What are "template custom keys" in the Player settings? 0 Answers