Search Unity

How to get reference of all Toggles from ToggleGroup?

Discussion in 'Scripting' started by leegod, Mar 30, 2017.

  1. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,476
    So I manually registered 8 toggles to 1 togglegroup.

    Unity docs just provide togglegroup.ActiveToggle() but this seems only returns Toggles that its state is [On].

    I want get all toggles regardless of its state is On or Off.

    Impossible with builtin unity ToggleGroup code?
     
  2. Novack

    Novack

    Joined:
    Oct 28, 2009
    Posts:
    844
    Yes it seems impossible. For some odd design choice, you cant retrieve the list of toggles from a ToggleGroup.
    Reference here:
    https://bitbucket.org/Unity-Technol...eGroup.cs?at=5.6&fileviewer=file-view-default

    The class seems pretty rudimentary, you also cannot simply get the single active one, need to resort to tricks and workarounds like this:
    http://answers.unity3d.com/questions/809412/is-there-a-better-way-to-access-the-single-active.html

    And you cant set the active one by providing an index...
     
  3. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    On the plus side, since the UI is open source, you can just grab the ToggleGroup source code, rename it to ToggleGroupEx (or something), and change the private toggle list to public.
     
  4. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,476
    I knew unity's source code is basically hidden, and maybe need to pay a lot for access source code, isn't it? Recently changed? Or UI part only is open source? How to access then?
     
  5. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    From that link:
    https://bitbucket.org/Unity-Technol...eGroup.cs?at=5.2&fileviewer=file-view-default

    Or from decompiled:
    Code (csharp):
    1.  
    2. // Decompiled with JetBrains decompiler
    3. // Type: UnityEngine.UI.ToggleGroup
    4. // Assembly: UnityEngine.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    5. // MVID: 7F607661-A55A-47C4-9E8D-7EC7AB288D3D
    6. // Assembly location: C:\Program Files (x86)\Unity\Editor\Data\UnityExtensions\Unity\GUISystem\UnityEngine.UI.dll
    7.  
    8. using System;
    9. using System.Collections.Generic;
    10. using System.Linq;
    11. using UnityEngine;
    12. using UnityEngine.EventSystems;
    13.  
    14. namespace UnityEngine.UI
    15. {
    16.   /// <summary>
    17.   ///
    18.   /// <para>
    19.   /// A component that represents a group of Toggles.
    20.   /// </para>
    21.   ///
    22.   /// </summary>
    23.   [AddComponentMenu("UI/Toggle Group", 32)]
    24.   [DisallowMultipleComponent]
    25.   public class ToggleGroup : UIBehaviour
    26.   {
    27.     [SerializeField]
    28.     private bool m_AllowSwitchOff = false;
    29.     private List<Toggle> m_Toggles = new List<Toggle>();
    30.  
    31.     /// <summary>
    32.     ///
    33.     /// <para>
    34.     /// Is it allowed that no toggle is switched on?
    35.     /// </para>
    36.     ///
    37.     /// </summary>
    38.     public bool allowSwitchOff
    39.     {
    40.       get
    41.       {
    42.         return this.m_AllowSwitchOff;
    43.       }
    44.       set
    45.       {
    46.         this.m_AllowSwitchOff = value;
    47.       }
    48.     }
    49.  
    50.     protected ToggleGroup()
    51.     {
    52.     }
    53.  
    54.     private void ValidateToggleIsInGroup(Toggle toggle)
    55.     {
    56.       if ((UnityEngine.Object) toggle == (UnityEngine.Object) null || !this.m_Toggles.Contains(toggle))
    57.         throw new ArgumentException(string.Format("Toggle {0} is not part of ToggleGroup {1}", new object[2]
    58.         {
    59.           (object) toggle,
    60.           (object) this
    61.         }));
    62.     }
    63.  
    64.     /// <summary>
    65.     ///
    66.     /// <para>
    67.     /// Notify the group that the given toggle is enabled.
    68.     /// </para>
    69.     ///
    70.     /// </summary>
    71.     /// <param name="toggle"/>
    72.     public void NotifyToggleOn(Toggle toggle)
    73.     {
    74.       this.ValidateToggleIsInGroup(toggle);
    75.       for (int index = 0; index < this.m_Toggles.Count; ++index)
    76.       {
    77.         if (!((UnityEngine.Object) this.m_Toggles[index] == (UnityEngine.Object) toggle))
    78.           this.m_Toggles[index].isOn = false;
    79.       }
    80.     }
    81.  
    82.     /// <summary>
    83.     ///
    84.     /// <para>
    85.     /// Toggle to unregister.
    86.     /// </para>
    87.     ///
    88.     /// </summary>
    89.     /// <param name="toggle">Unregister toggle.</param>
    90.     public void UnregisterToggle(Toggle toggle)
    91.     {
    92.       if (!this.m_Toggles.Contains(toggle))
    93.         return;
    94.       this.m_Toggles.Remove(toggle);
    95.     }
    96.  
    97.     /// <summary>
    98.     ///
    99.     /// <para>
    100.     /// Register a toggle with the group.
    101.     /// </para>
    102.     ///
    103.     /// </summary>
    104.     /// <param name="toggle">To register.</param>
    105.     public void RegisterToggle(Toggle toggle)
    106.     {
    107.       if (this.m_Toggles.Contains(toggle))
    108.         return;
    109.       this.m_Toggles.Add(toggle);
    110.     }
    111.  
    112.     /// <summary>
    113.     ///
    114.     /// <para>
    115.     /// Are any of the toggles on?
    116.     /// </para>
    117.     ///
    118.     /// </summary>
    119.     public bool AnyTogglesOn()
    120.     {
    121.       return (UnityEngine.Object) this.m_Toggles.Find((Predicate<Toggle>) (x => x.isOn)) != (UnityEngine.Object) null;
    122.     }
    123.  
    124.     /// <summary>
    125.     ///
    126.     /// <para>
    127.     /// Returns the toggles in this group that are active.
    128.     /// </para>
    129.     ///
    130.     /// </summary>
    131.     ///
    132.     /// <returns>
    133.     ///
    134.     /// <para>
    135.     /// The active toggles in the group.
    136.     /// </para>
    137.     ///
    138.     /// </returns>
    139.     public IEnumerable<Toggle> ActiveToggles()
    140.     {
    141.       return Enumerable.Where<Toggle>((IEnumerable<Toggle>) this.m_Toggles, (Func<Toggle, bool>) (x => x.isOn));
    142.     }
    143.  
    144.     /// <summary>
    145.     ///
    146.     /// <para>
    147.     /// Switch all toggles off.
    148.     /// </para>
    149.     ///
    150.     /// </summary>
    151.     public void SetAllTogglesOff()
    152.     {
    153.       bool flag = this.m_AllowSwitchOff;
    154.       this.m_AllowSwitchOff = true;
    155.       for (int index = 0; index < this.m_Toggles.Count; ++index)
    156.         this.m_Toggles[index].isOn = false;
    157.       this.m_AllowSwitchOff = flag;
    158.     }
    159.   }
    160. }
    161.  
    162.  
    The toggles are stored in a List called 'm_Toggles'.

    You should be able to reflect it out like follows (done as an extension method):
    Code (csharp):
    1.  
    2. public static class ToggleGroupExtensions
    3. {
    4.  
    5.     private static System.Reflection.FieldInfo _toggleListMember;
    6.  
    7.     /// <summary>
    8.     /// Gets the list of toggles. Do NOT add to the list, only read from it.
    9.     /// </summary>
    10.     /// <param name="grp"></param>
    11.     /// <returns></returns>
    12.     public static IList<Toggle> GetToggles(this ToggleGroup grp)
    13.     {
    14.         if(_toggleListMember == null)
    15.         {
    16.             _toggleListMember = typeof(ToggleGroup).GetField("m_Toggles", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
    17.             if (_toggleListMember == null)
    18.                 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.");
    19.         }
    20.         return _toggleListMember.GetValue(grp) as IList<Toggle>;
    21.     }
    22.  
    23.     public static int Count(this ToggleGroup grp)
    24.     {
    25.         return GetToggles(grp).Count;
    26.     }
    27.  
    28.     public static Toggle Get(this ToggleGroup grp, int index)
    29.     {
    30.         return GetToggles(grp)[index];
    31.     }
    32.  
    33. }
    34.  
     
    Colin_MacLeod and bz_tian like this.
  7. Marek_Bakalarczuk

    Marek_Bakalarczuk

    Joined:
    Dec 28, 2012
    Posts:
    114
    Really? ToggleGroup is so wrong written thast don't have set all toggles on method?
     
    VirtualPierogi likes this.
  8. Matthew-I

    Matthew-I

    Joined:
    Jun 27, 2020
    Posts:
    1

    You can simply extend ToggleGroup and return m_Toggles in a custom getter function;

    For instance :

    Code (CSharp):
    1. public class ToggleGroupPublicToggles : ToggleGroup
    2. {
    3.  
    4.     public List<Toggle> GetToggles()
    5.     {
    6.         return m_Toggles;
    7.     }
    8.  
    9. }
    Apply that script wherever needed instead of the default ToggleGroup one.
     
    tonialatalo likes this.
  9. ShawnFeatherly

    ShawnFeatherly

    Joined:
    Feb 22, 2013
    Posts:
    57
    m_Toggles doesn't seem to contain the list of toggles ordered to match the hierarchy. If you can rely on the common hierarchy arrangement, of ToggleGroup is the parent object of several Toggles, it will allow reliable ordering. In other words, if you can maintain a specific structure for ToggleGroups in a Unity scenes' hierarchy you can have consistent ordering between that hierarchy and the list of Toggles.

    Example (from http://answers.unity.com/answers/1332394/view.html):
    myToggleGroup.transform.GetChild(myIndexOfToggle).GetComponent<UnityEngine.UI.Toggle>().isOn = true;