This question has certainly been asked before, but it’s never gotten answered, and I’ve tried everything I can think of.
How can I get a EditorGUILayout.Foldout to remember its state when the object that has the script that it’s controlling has been deselected and then reselected?
If I initialize the boolean (foldout1) as true, the Foldout will always be open when I return to the object - if false, then it will always be folded up when I return.
@CustomEditor (test)
class testEditor extends Editor {
var foldout1 : boolean = true;
function OnInspectorGUI () {
foldout1 = EditorGUILayout.Foldout(foldout1, "Something");
if (foldout1) {
target.something = EditorGUILayout.IntSlider ("Something",target.something, 0, 100);
}
}
}
Would love to see a working example, and I bet I’m not the only one.
What you can do is set the foldout to use the isExpanded property of one of the serializedObject properties you want to show inside the expanded area. this will work with any property type, it doesn’t have to be one that actually expands, it could be a text field…
So if you had
class MyTestClass : MonoBehaviour
{
string myTextField;
}
You could then have a custom editor for that like this
[CustomEditor(typeof(MyTestClass),true)]
public class MyTestClassEditor : Editor
{
public override void OnInspectorGUI(){
SerializedProperty myTextField = serializedObject.FindProperty ("myTextField");
myTextField.isExpanded = EditorGUILayout.Foldout (myTextField.isExpanded, "My Foldout");
if(myTextField.isExpanded){
EditorGUILayout.PropertyField (myTextField);
}
}
}
Editors are created if an object of it’s type has been selected and are destroyed when the object gets deselected. If you want the editor to save the state individual for each object, you have to use a variable in the target script, which is not nice, since it blows up your class. However, you can surround the variable with:
#if UNITY_EDITOR
[HideInInspector]
var foldout : boolean = true;
#endif
This way the variable only exists when you run your game in the editor. When you create a build it will not be there.
But the easiest way is to use a static variable in your editor. This will remember the state for the editor, not an individual object. If that’s what you want, static is what you need
class testEditor extends Editor
{
static var foldout1 : boolean = true;
[...]
#if UNITY_EDITOR
[HideInInspector]
var foldout : boolean = true;
#endif
This may be a ticking time bomb if you want your code to run on iOS, and possibly other platforms. It seems that Unity does not support having variables in the editor that do not appear in the runtime in every case. I tried using #if UNITY_EDITOR to compile out variables in the runtime version like this and it worked fine for Windows/Mac standalone builds, but when I moved it to iOS I got mysterious crashes during level load.
I’m not sure exactly what is going on, but I believe Unity is serializing those variables in the editor, but failing to deserialize them in the runtime (because they are compiled out) though the data is there in the input stream. This results in corrupted game object data and often leads to crashes.
It doesn’t always happen, but one situation where it does happen almost consistently is with an array of classes marked Serializable, something like this:
[System.Serializable]
class MyClass
{
int var1;
#if UNITY_EDITOR
int var2;
#endif
}
class MyComponent : MonoBehaviour
{
public MyClass[] myItems;
}
I wrestled for most of a day with a crash bug caused by a similar bit of code. Removing the #if UNITY_EDITOR solved the problem for me, so I thought I’d share this in the hopes of saving someone else from the same fate.
Not sure if it’s the best way to do it, but I achieved this effect by saving the state using the EditorPrefs class in the OnEnable and OnDestroy methods of the custom editor script: