- Home /
Is there a better way to access the single active Toggle in a ToggleGroup?
I'm very confused by the API related to Unity 4.6's ToggleGroup.
In particular, the documentation doesn't even mention the method ToggleGroup.ActiveToggles()
But even weirder, why is the only way to get at the toggles via an enumeration? The documentation on ToggleGroup clearly states that only one may be active/selected at a time. So why not just have a single myToggleGroup.ActiveToggle()
to return that one value?
Instead I seem to have to do something like:
IEnumerator<Toggle> toggleEnum = myToggleGroup.ActiveToggles().GetEnumerator();
toggleEnum.MoveNext();
Toggle toggle = toggleEnum.Current;
... which seems unnecessarily verbose and just generally unintuitive.
Am I misunderstanding something about ToggleGroups or this API?
Answer by Bunny83 · Oct 15, 2014 at 12:15 AM
Yes, you are right. This is indeed a bit strange. I just looked at the code and as the documentation states, only one Toggle can be active at the same time since each toggle report it's state change to the group and the group will iterate through all toggles and turn them all off except the one clicked.
Maybe they don't want to to actually interact with the group. The only method they have documented is just the "AnyTogglesActive" method.
You could use the "onValueChanged" event of each individual toggle to get informed when a toggle changed it's state. Unfortunately that event only has the state as parameter and not a Toggle reference which would be more useful as you could use the same handler for all toggles.
At the moment it doesn't look like there's a way to get a list of all toggles in a group (besides using reflection).
Keep in mind that you're using a beta version of Unity, so you are a beta tester. If you want to suggest an improvement, post it either on the beta forum or on the Feedback page. Don't forget to first search if a similar change has already been suggested.
edit
In the meantime you could simply write a extension method like this:
using UnityEngine.UI;
using System.Linq;
public static class ToggleGroupExtension
{
public static Toggle GetActive(this ToggleGroup aGroup)
{
return aGroup.ActiveToggles().FirstOrDefault();
}
}
So you could simply use:
Toggle active = myToggleGroup.GetActive();
Since it seems like I'm not just missing something obvious, I've posted as a suggestion to the beta feedback page. Also, the extension suggestion is handy in the meantime, thanks! ($$anonymous$$inor typo if anyone else is trying to use this solution: FirstOfDefault -> FirstOrDefault)
this extension is nice. note that one has to add using UnityEngine.UI;
to use Toggle and ToggleGroup classes.
As of October 22, 2015, ActiveToggles() returns IEnumerable<Toggle>
in Unity 5.2.1p4. There is no more FirstOrDefault()
method to call.
I believe it has always returned IEnumerable. You need to add the "using System.Linq;" line or you won't see the FirstOrDefault() method, though. (It's an extension method added by Linq)
Answer by bugglind · Nov 01, 2016 at 08:33 PM
Import System.Linq namespace using the using keyword. Then do:
toggleGroup.ActiveToggles().FirstOrDefault()
This returns the first element of an enumeration or the default value of the enumeration type (null for nullable types, such as Toggle) if the list is empty.
System.Linq is stupidly useful for manipulating any kind of enumeration. Whenever you need to do something stupid or painful with a foreach loop, stop and see if Linq will make it stupidly easy.
Answer by gcrozariol · Feb 20, 2019 at 08:13 PM
I know this topic has been opened for a long time, but I had that doubt myself and I figured out you can easily get the toggle that is turned on simply by creating a foreach loop on the toggle group, something like this:
[SerializeField] private ToggleGroup myToggleGroup;
[SerializeField] private Toggle myToggle;
foreach (var toggle in myToggleGroup.ActiveToggles())
{
if (toggle.isOn)
{
myToggle = toggle;
}
}
Hope this helps!
That's pretty much what the Linq extension "FirstOrDefault" does which I used in my answer. Though it does something like this:
foreach (var toggle in myToggleGroup.ActiveToggles())
{
myToggle = toggle;
break;
}
So my solution return the first element from the ActiveToggles array (if there is any) while your solution returns the last (if there is any). Though as i said in my answer the returned array only contains at max one element (though it could be an empty array as well)
Note that your isOn check is unnecessary and redundant. If you look at my last comment above, the "ActiveToggles" method already takes care of that. So ActiveToggles only returns elements which have their isOn property set to true.
The inOn check is indeed unnecessary and redundant. Thanks for pointing that out!
Answer by IARI · Jul 28, 2020 at 03:19 PM
Necropost from 2020:
The m_Toggles field at least is protected (don't know if that as a change). So you can access it without reflection in an actual togglegroup class inheriting from Unitys ToggleGroup you write yourself - useful methods and fields.
Sorry but I have to put this in clear words, as this is not the only place in unity where this is the case: I hope that by now they do some more quality checking on their api designs. This api simply isn't well designed. Whoever did this at the time either didn't have a proper amount time, didn't really know what they were doing.