I made a class which inherits the ToggleGroup which has an OnChange event:
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
public class BetterToggleGroup : ToggleGroup {
public delegate void ChangedEventHandler(Toggle newActive);
public event ChangedEventHandler OnChange;
public void Start() {
foreach (Transform transformToggle in gameObject.transform) {
var toggle = transformToggle.gameObject.GetComponent<Toggle>();
toggle.onValueChanged.AddListener((isSelected) => {
if (!isSelected) {
return;
}
var activeToggle = Active();
DoOnChange(activeToggle);
});
}
}
public Toggle Active() {
return ActiveToggles().FirstOrDefault();
}
protected virtual void DoOnChange(Toggle newactive)
{
var handler = OnChange;
if (handler != null) handler(newactive);
}
}
Add the above class to your project and replace the ToggleGroup script in the inspector with it.
The class requires that all of the ToggleGroupās Toggles are children of it:
To listen to the event, from another script use the following code:
@thatshowifeel had a good answer. Hereās a slightly improved, more modern version:
using System.Linq;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
[RequireComponent(typeof(ToggleGroup))]
public class EventToggleGroup : MonoBehaviour
{
[System.Serializable]
public class ToggleEvent : UnityEvent<Toggle> { }
[SerializeField]
public ToggleEvent onActiveTogglesChanged;
[SerializeField]
private Toggle[] _toggles;
private ToggleGroup _toggleGroup;
private void Awake()
{
_toggleGroup = GetComponent<ToggleGroup>();
}
// Start is called before the first frame update
void OnEnable()
{
foreach (Toggle toggle in _toggles)
{
if (toggle.group != null && toggle.group != _toggleGroup)
{
Debug.LogError($"EventToggleGroup is trying to register a Toggle that is a member of another group.");
}
toggle.group = _toggleGroup;
toggle.onValueChanged.AddListener(HandleToggleValueChanged);
}
}
void HandleToggleValueChanged(bool isOn)
{
if (isOn)
{
onActiveTogglesChanged?.Invoke(_toggleGroup.ActiveToggles().FirstOrDefault());
}
}
void OnDisable()
{
foreach (Toggle toggle in _toggleGroup.ActiveToggles())
{
toggle.onValueChanged.RemoveListener(HandleToggleValueChanged);
toggle.group = null;
}
}
}
To use:
Add EventToggleGroup as a sibling of ToggleGroup.
Drag Toggle into EventToggleGroup.toggles.
Add something to listen to onActiveToggleChanged. Note: It may return null if no toggles are selected!
Changes:
*Rather than assuming the Toggles are children of the ToggleGroup transform you must explicitly specify the toggles. This allows you to put the ToggleGroup/EventToggleGroup wherever you want in the GameObject hierarchy.
*It is not necessary to specify the āgroupā on the individual Toggle components anymore. (Note: This does allow a toggle to be a member of multiple EventToggleGroups! Donāt do this.)
*Rather than deriving from ToggleGroup, EventToggleGroup is a sibling component of ToggleGroup. This conforms to the Entity/Component model better.
*Rather than raising a C# event, it raises a UnityEvent which allows us to hook up event listeners in the UnityEditor AND code.
Great solution. Thanks.
I added a small function to set one option to āonā and disable the others (useful for radio buttons).
/**
* Programmatically set a toggle to on (and set all others to off).
*/
public void SetToggle(Toggle toggle)
{
foreach (Toggle t in Toggles)
{
bool isOn = toggle == t;
t.isOn = isOn;
Debug.Log(("setting " + t.name + " to " + isOn));
}
}