Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 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 /
avatar image
9
Question by phoberman · Feb 11, 2012 at 11:15 PM · editorguilayout

EditorGUILayout.Foldout - no way to remember state?

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.

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

6 Replies

· Add your reply
  • Sort: 
avatar image
7
Best Answer

Answer by Bunny83 · Feb 12, 2012 at 02:51 AM

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;
     [...]
Comment
Add comment · Show 3 · 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 phoberman · Feb 12, 2012 at 04:00 AM 0
Share

Perfect - thanks!

avatar image vexe · Feb 01, 2014 at 02:51 PM 1
Share

I also suggest to use a nested class inside your $$anonymous$$B to hold the editor data - just to reduce the clutter.

avatar image oferei · Aug 14, 2015 at 05:39 PM 0
Share

I suggest adding NonSerialized as well - to prevent the members from being saved to the scene.

avatar image
12

Answer by davidosullivan · Mar 26, 2016 at 09:01 AM

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);
              }
        }
 }
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 IronLionZion · Jan 07, 2017 at 12:18 AM 1
Share

This seems to be the best solution. You don't have to store any extra bool value or anything of the sort.

avatar image Emiles · Feb 13, 2017 at 01:31 PM 0
Share

Unfortunately I can't seem to make this work for a List of objects. I can't work out why, but its seems to treat all objects in the list as having the same isExpanded Value.

avatar image Damjan-Mozetic · Sep 24, 2018 at 05:00 PM 0
Share

Don't know if it worked before of not, but in 2018.2 it works beautifully, even for Lists. Great solution.

avatar image PixelFireXY · Apr 15 at 07:35 AM 0
Share

The best solution, thanks! Works in Unity 2020.3.31f1

avatar image
5

Answer by Mikilo · Dec 08, 2013 at 03:11 AM

As I can see, we are many to seek for a fold trick.

I did a little tool to fulfil the job.

 using System.Collections.Generic;
 
 public static class FoldRestorer
 {
     private static Dictionary<int, bool>    folds = new Dictionary<int,bool>();
 
     public static bool    GetFold(int hash)
     {
         if (folds.ContainsKey(hash) == false)
         {
             folds[hash] = false;
             return false;
         }
         return folds[hash];
     }
 
     public static void    SetFold(int hash, bool value)
     {
         folds[hash] = value;
     }
 }

After the tool, the example through a property drawer.

It is a little bit messy, but it is optimized.

         int    hash = property.propertyPath.GetHashCode();
         EditorGUI.BeginChangeCheck();
         bool    b = EditorGUI.Foldout(position, FoldRestorer.GetFold(hash), "Fold");
         if (EditorGUI.EndChangeCheck() == true)
             FoldRestorer.SetFold(hash, b);

It has been tested on Unity 4.3.

You can add a method into FoldRestorer to replace the block above and be more efficient.

Comment
Add comment · Show 1 · 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 chadfranklin47 · Feb 28 at 03:18 PM 0
Share

Beautiful!

avatar image
4

Answer by Troyminator · Jan 03, 2013 at 08:00 PM

Just a warning to anyone who implements this:

 #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.

Comment
Add comment · Show 2 · 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 Bunny83 · Jan 03, 2013 at 10:40 PM 1
Share

Yes, good point. The way Unity's serializer works could break it. Unity will serialize the data but can't deserialize it in the build.

It's actually better to avoid such things in general ;) The inspector should work the same for every object, so i would always go for the static or EditorPrefs way.

Of course you can't store the state per object this way but if you really need that you could try using a dictionary (stored in the Editor class and not your runtime class) which holds the state for different objects. The only difficulty i see is getting a unique key for each object, but i guess GetInstanceID should do the job. It's not guaranteed to be unique across sessions, reimports and such but for this purpose it's enough. The static variables are cleared anyway each recompile ;)

avatar image ivaylo5ev Bunny83 · Oct 16, 2017 at 11:02 AM 0
Share

@Bunny83, thanks for pointing me to the EditorPrefs, I was not aware that functionality existed. Looks to me the better alternative to using static fields for keeping the editor state, and I hope the settings get preserved across re-opening the Unity editor itself

To everyone else, I'd recommend using some external to the object storage for the editor state, because keeping editor-only data inside the game object is a bad design decision according to my perspective. It needlessly pollutes the object, causes serialization issues as seen above and increases the memory footprint of the component within the game -- the memory will be there even when the game is ran as standalone, without the editor environment.

avatar image
1

Answer by Radmer · Aug 27, 2015 at 12:21 PM

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:

 void OnDestroy()
 {
     EditorPrefs.SetBool("FoldedOut", foldedout);
 }
     
 void OnEnable()
 {
     foldedout = EditorPrefs.GetBool("FoldedOut", false);
 }

With this approach the state will also be saved between Unity sessions.

Comment
Add comment · Show 2 · 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 Mikilo · Aug 27, 2015 at 12:37 PM 0
Share

If it is used in only one place it works. You it is used in many places, it wont.

avatar image MaxKarpinsky Mikilo · Mar 19, 2018 at 01:17 PM 0
Share

It's possible to just use your created hash as string for key to store in EditorPrefs, which seems like more suitable way to store those kind of things, and save between sessions. Combination is always the best way if it brings something useful.

  • 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.

Follow this Question

Answers Answers and Comments

18 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

Related Questions

Custom Inspector with field like Camera culling mask 2 Answers

EditorGUI, EditorGUILayout, GUI, GUILayout... pshhh... WHEN TO USE WHAT?! 3 Answers

Editor - GUILayout.BeginArea does not expand ScrollView 2 Answers

Player Settings messed up 1 Answer

Is there a way to change the text size for a Vector3 PropertyField in a custom Inspector? 0 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