Getting and Setting ToggleGroup toggle values

I have some toggle groups that I want to load and save.
I want to be able to save a string to Persistent storage matching the currently selected toggle.

So for example if I have three toggles with text ONE, TWO, THREE I want to save ONE if first one selected.
I think this seems to be working:

IEnumerator<Toggle> toggleEnumCallsign = callsignToggleGroup.GetComponent<ToggleGroup>().ActiveToggles().GetEnumerator();
        toggleEnumCallsign.MoveNext();
        Toggle callsignToggle = toggleEnumCallsign.Current;
        Text callsignText = callsignToggle.GetComponentInChildren <Text> ();
            optionsdata.callsignToggleGroup  = callsignText.text;
            Debug.Log ("Set to " + callsignText.text);

So this seems to be writing the correct string to Debug.Log

How can I do the reverse though?
I want to take the text string from the optionsdata variable.
Then match it to the text on the relevent toggle.
Then set that toggle to on.

Sounds like I need to be using:

myToggleGroup.NotifyEnabled(myOneToggleOfThisGroup);
myToggle.isOn = true;

But I have no idea how to match it to the text on my toggles.

Or is there a better way to do this?
Is there not a togglegroup get/set method?

Thanks

Actually, I thought I had it working but it now seems to be erroring on :
string callsignText = callsignToggle.GetComponentInChildren().text ;

with an object refrenece not set to an instance

Well I created a Panel with a toggle group and 3 toggles. Then created a Tester script which i referenced my panel:

Script testing your code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Tester : MonoBehaviour {
    public GameObject myPanel;
 
    void Update () {
        if (Input.GetKeyDown(KeyCode.A))
        {
            IEnumerator<Toggle> toggleEnumCallsign = myPanel.GetComponent<ToggleGroup>().ActiveToggles().GetEnumerator();
            toggleEnumCallsign.MoveNext();
            Toggle callsignToggle = toggleEnumCallsign.Current;
            Text callsignText = callsignToggle.GetComponentInChildren<Text>();

            Debug.Log("Set to " + callsignText.text);
        
        }
    }
}

I was able to to get the correct Text of the toggle. Your code seems fine for getting the the correct text.

I looked into the ToggleGroup code here: https://bitbucket.org/Unity-Technologies/ui/src/a3f89d5f7d145e4b6fa11cf9f2de768fea2c500f/UnityEngine.UI/UI/Core/?at=2017.3

It looks like ToggleGroup doesn’t have an easy way to just get all the Toggles in a list. It stores them in a private List: m_toggles. I think the easiest way to save and store these toggle values is with PlayerPrefs. This is just a flat text file unity uses to load/store data. Its insecure as players can access it, but perfect for UI things.

We have two options:

  1. Copy ToggleGroup.cs from the above link and then modify it so the list is public
  2. Use Reflection to get at the list.

I’m going to use option 2. The solution will involve 3 major topics you might want to research to fully understand it. You can google all 3 of these to find out more information

  1. PlayerPrefs – easy topic
  2. C# Class Extensions – easy topic
  3. C# Reflection – medium/hard topic

First you need to make an extension script that uses reflection to get at the Toggle List:
(This code was originally written by lordofduct)
ToggleGroupExtensions.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public static class ToggleGroupExtensions
{

    private static System.Reflection.FieldInfo _toggleListMember;

    public static IList<Toggle> GetToggles(this ToggleGroup grp)
    {
        if (_toggleListMember == null)
        {
            _toggleListMember = typeof(ToggleGroup).GetField("m_Toggles", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
            if (_toggleListMember == null)
                throw new System.Exception("UnityEngine.UI.ToggleGroup source code must have changed in latest version and is no longer compatible with this version of code.");
        }
        return _toggleListMember.GetValue(grp) as IList<Toggle>;
    }

    public static int Count(this ToggleGroup grp)
    {
        return GetToggles(grp).Count;
    }

    public static Toggle Get(this ToggleGroup grp, int index)
    {
        return GetToggles(grp)[index];
    }

}

This has 3 methods. Get a List of all your toggles, Get a Count of toggles, and Get a specific toggle by index. You can just make this script and leave it in your project it doesn’t need to be attached to any Game Object.

Here is an example of how to use this to store and load the Toggle Setting. I just use the “A” key to store my toggle value, and it loads toggles value on Start(). You can place these functions in whatever appropriate spot you need:

Tester Script to Load/Save Toggles

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Tester : MonoBehaviour {
    public GameObject myPanel;
 
    void Start()
    {
        int x = PlayerPrefs.GetInt("ToggleGroupName",0);
        ToggleGroup tg = myPanel.GetComponent<ToggleGroup>();
        IList<Toggle> toggles = tg.GetToggles();
        tg.SetAllTogglesOff();
        toggles[x].isOn = true;

    }

    void Update () {
        if (Input.GetKeyDown(KeyCode.A))
        {
            ToggleGroup tg = myPanel.GetComponent<ToggleGroup>();
            IList<Toggle> toggles = tg.GetToggles();

            bool found = false;
            for (int i = 0; !found && i < tg.Count();++i)
            {
                if (toggles[i].isOn)
                {
                    found = true;
                    PlayerPrefs.SetInt("ToggleGroupName", i);
                }
            }
        
        }
    }
}

Thanks for the detailed post, and for taking the time to play about.
That does seem an insane amount of work for something so simple.

Unless there is a simpler way I’m thinking I may even just create my own toggle groups instead of using Unity’s.
Create 3 toggles.
Set a trigger on each to call a script on change of value.
Set the other 2 in the group to off.
Set my variable to the value from the active toggle.
Save out all my variables to a file once done.

Which does get me wondering what the point of Unity’s toggle groups are. Without being able to easily get the value, I dont see the point.

Edit. Maybe the easiest way is to let the toggle group keep the uniqueness between the toggles.
But have a trigger on each toggle that when it is clicked I set a variable to the toggle.name, thus always having that variable set to the active toggle.
Then when I load in, I guess I just need a way of simulating a ‘click’ on the correct toggle.

Anyway, its been a long day. I think I’ll have a good read through your post and code tomorrow.
Thanks again.

The other answer given is nice. I thought I would add another option. If I was doing it, I might just create a small script that has a list of toggles in the group. When I choose a toggle, I set the corresponding value, but by integer index (same as each toggle’s in the list). Loading it back up could be as easy as an index into the list for turning it on.

Thanks.
I think you are suggesting something similar to what I was starting to think.

Just not 100 percent sure what you mean by "
When I choose a toggle, I set the corresponding value, but by integer index (same as each toggle’s in the list). "

Thanks

Well, I think we were talking about very similar ideas. Your idea was to use the string, though, whereas mine was to use an integer. Say, you have a script that goes on … maybe the toggle group, and you make sure each toggle goes into a list on that script. Now, they are in order : 0 → 2 (index).

When you select a toggle, one of the actions it can do, in addition to its normal functionality, is to tell the new script it’s the active one (by its index value). Later, when reloading, use the saved int to turn on the corresponding toggle (from the list). :slight_smile:

I feel as though I kind of repeated my last post, but perhaps I said something a bit clearer? Does it make sense?

Thanks, yes, that makes sense. I will see what I can get working.
I am very surprised the togglegroup doesn’t have this functionality already though. Very strange.

Thanks again.

if you set public Toggle myToggle1, myToggle2, my Toggle2 (assign in inspector), you can then save playerprefs string (“myToggleOption” with "one, “two” or “three”, based on if (myToggle1.isOn). Them load playerprefs and with if statement use isOn method to activate toggle if (PlayerPrefs.GetString(“myToggleOption”) == “one”). Since others are on the group they will unselect automatic… Did not try this solution, but I think i can work!