using System; using System.Linq; using System.Collections.Generic; using UnityEngine.EventSystems; namespace UnityEngine.UI { [AddComponentMenu("UI (Canvas)/Toggle Group", 31)] [DisallowMultipleComponent] /// /// A component that represents a group of UI.Toggles. /// /// /// When using a group reference from a `UI.Toggle`. Only one member of a group can be on at a time. /// public class ToggleGroup : UIBehaviour { [SerializeField] private bool m_AllowSwitchOff = false; /// /// Is it allowed that no toggle is switched on? /// /// /// If this setting is enabled, pressing the toggle that is currently switched on will switch it off, so that no toggle is switched on. If this setting is disabled, pressing the toggle that is currently switched on will not change its state. /// Note that even if allowSwitchOff is false, the Toggle Group will not enforce its constraint right away if no toggles in the group are switched on when the scene is loaded or when the group is instantiated. It will only prevent the user from switching a toggle off. /// public bool allowSwitchOff { get { return m_AllowSwitchOff; } set { m_AllowSwitchOff = value; } } protected List m_Toggles = new List(); protected ToggleGroup() {} /// /// Because all the Toggles have registered themselves in the OnEnabled, Start should check to /// make sure at least one Toggle is on in groups that do not AllowSwitchOff /// protected override void Start() { EnsureValidState(); base.Start(); } protected override void OnEnable() { EnsureValidState(); base.OnEnable(); } private void ValidateToggleIsInGroup(Toggle toggle) { if (toggle == null || !m_Toggles.Contains(toggle)) throw new ArgumentException(string.Format("Toggle {0} is not part of ToggleGroup {1}", new object[] {toggle, this})); } /// /// Notify the group that the given toggle is on. /// /// The toggle that got triggered on. /// If other toggles should send onValueChanged. public void NotifyToggleOn(Toggle toggle, bool sendCallback = true) { ValidateToggleIsInGroup(toggle); // disable all toggles in the group for (var i = 0; i < m_Toggles.Count; i++) { if (m_Toggles[i] == toggle) continue; if (sendCallback) m_Toggles[i].isOn = false; else m_Toggles[i].SetIsOnWithoutNotify(false); } } /// /// Unregister a toggle from the group. /// /// The toggle to remove. public void UnregisterToggle(Toggle toggle) { if (m_Toggles.Contains(toggle)) m_Toggles.Remove(toggle); } /// /// Register a toggle with the toggle group so it is watched for changes and notified if another toggle in the group changes. /// /// The toggle to register with the group. public void RegisterToggle(Toggle toggle) { if (!m_Toggles.Contains(toggle)) m_Toggles.Add(toggle); } /// /// Ensure that the toggle group still has a valid state. This is only relevant when a ToggleGroup is Started /// or a Toggle has been deleted from the group. /// public void EnsureValidState() { if (!allowSwitchOff && !AnyTogglesOn() && m_Toggles.Count != 0) { m_Toggles[0].isOn = true; NotifyToggleOn(m_Toggles[0]); } IEnumerable activeToggles = ActiveToggles(); if (activeToggles.Count() > 1) { Toggle firstActive = GetFirstActiveToggle(); foreach (Toggle toggle in activeToggles) { if (toggle == firstActive) { continue; } toggle.isOn = false; } } } /// /// Are any of the toggles on? /// /// Are and of the toggles on? public bool AnyTogglesOn() { return m_Toggles.Find(x => x.isOn) != null; } /// /// Returns the toggles in this group that are on. /// /// The toggles in the group that are on. /// /// This only checks the on or off state, not the GameObject's active state. /// public IEnumerable ActiveToggles() { return m_Toggles.Where(x => x.isOn); } /// /// Returns the first toggle that is on. /// /// The first toggle that is on, or `null` if none are on. /// /// This only checks the on or off state, not the GameObject's active state. /// public Toggle GetFirstActiveToggle() { IEnumerable activeToggles = ActiveToggles(); return activeToggles.Count() > 0 ? activeToggles.First() : null; } /// /// Switch all toggles off. /// /// /// This method can be used to switch all toggles off, regardless of whether the allowSwitchOff property is enabled or not. /// public void SetAllTogglesOff(bool sendCallback = true) { bool oldAllowSwitchOff = m_AllowSwitchOff; m_AllowSwitchOff = true; if (sendCallback) { for (var i = 0; i < m_Toggles.Count; i++) m_Toggles[i].isOn = false; } else { for (var i = 0; i < m_Toggles.Count; i++) m_Toggles[i].SetIsOnWithoutNotify(false); } m_AllowSwitchOff = oldAllowSwitchOff; } } }