UIGU源码分析6:Toggle 和 ToggleGroup

源码6:Toggle 和 ToggleGroup

Toggle

public class Toggle : Selectable, IPointerClickHandler, ISubmitHandler, ICanvasElement
{
    /// <summary>
    /// Display settings for when a toggle is activated or deactivated.
    /// </summary>
    public enum ToggleTransition
    {
        /// <summary>
        /// Show / hide the toggle instantly
        /// </summary>
        None,

        /// <summary>
        /// Fade the toggle in / out smoothly.
        /// </summary>
        Fade
    }

    [Serializable]
    /// <summary>
    /// UnityEvent callback for when a toggle is toggled.
    /// </summary>
    public class ToggleEvent : UnityEvent<bool>
    {}

    /// <summary>
    /// Transition mode for the toggle.
    /// </summary>
    public ToggleTransition toggleTransition = ToggleTransition.Fade;

    /// <summary>
    /// Graphic the toggle should be working with.
    /// </summary>
    public Graphic graphic;

    [SerializeField]
    private ToggleGroup m_Group;

    /// <summary>
    /// Group the toggle belongs to.
    /// </summary>
    public ToggleGroup group
    {
        get { return m_Group; }
        set
        {
            SetToggleGroup(value, true);
            PlayEffect(true);
        }
    }

    /// <summary>
    /// Allow for delegate-based subscriptions for faster events than 'eventReceiver', and allowing for multiple receivers.
    /// </summary>

    public ToggleEvent onValueChanged = new ToggleEvent();

    // Whether the toggle is on
    [Tooltip("Is the toggle currently on or off?")]
    [SerializeField]
    private bool m_IsOn;
    
    ...
    
}

Toggle继承了Selectable, IPointerClickHandler, ISubmitHandler, ICanvasElement,(ICanvasElement,是Canvas渲染的时候调用的接口,后面文章再分析),Toggle有个重要的bool变量m_IsOn(对应成员属性IsOn),表示是否被勾选。还添加了一个UnityEvent类型的事件onValueChanged,用于外部监听m_IsOn是否改变。

IPointerClickHandler 和 ISubmitHandler 响应方式和Button一样 这里看下具体响应后具体做了什么

        public virtual void OnPointerClick(PointerEventData eventData)
        {
            if (eventData.button != PointerEventData.InputButton.Left)
                return;

            InternalToggle();
        }
  private void InternalToggle()
        {
            if (!IsActive() || !IsInteractable())
                return;

            isOn = !isOn;
        }
   public bool isOn
    {
        get { return m_IsOn; }

        set
        {
            Set(value);

    void Set(bool value, bool sendCallback = true)
    {
        if (m_IsOn == value)
            return;

        // if we are in a group and set to true, do group logic
        m_IsOn = value;
        if (m_Group != null && m_Group.isActiveAndEnabled && IsActive())
        {
            if (m_IsOn || (!m_Group.AnyTogglesOn() && !m_Group.allowSwitchOff))
            {
                m_IsOn = true;
                m_Group.NotifyToggleOn(this, sendCallback);
            }
        }

        // Always send event when toggle is clicked, even if value didn't change
        // due to already active toggle in a toggle group being clicked.
        // Controls like Dropdown rely on this.
        // It's up to the user to ignore a selection being set to the same value it already was, if desired.
        PlayEffect(toggleTransition == ToggleTransition.None);
        if (sendCallback)
        {
            UISystemProfilerApi.AddMarker("Toggle.value", this);
            onValueChanged.Invoke(m_IsOn);
         }
       }
       
       
        /// <summary>
        /// Play the appropriate effect.
        /// </summary>
        private void PlayEffect(bool instant)
        {
            if (graphic == null)
                return;

#if UNITY_EDITOR
            if (!Application.isPlaying)
                graphic.canvasRenderer.SetAlpha(m_IsOn ? 1f : 0f);
            else
#endif
            graphic.CrossFadeAlpha(m_IsOn ? 1f : 0f, instant ? 0f : 0.1f, true);
        }

可以看到点击后主要是设置m_IsOn状态 如果当前Toggle设置了ToggleGroup就会将当前状态通知到ToggleGroup 里 。 然后执行状态改变的表现 执行onValueChanged事件


    private void SetToggleGroup(ToggleGroup newGroup, bool setMemberValue)
    {
        // Sometimes IsActive returns false in OnDisable so don't check for it.
        // Rather remove the toggle too often than too little.
        if (m_Group != null)
            m_Group.UnregisterToggle(this);

        // At runtime the group variable should be set but not when calling this method from OnEnable or OnDisable.
        // That's why we use the setMemberValue parameter.
        if (setMemberValue)
            m_Group = newGroup;

        // Only register to the new group if this Toggle is active.
        if (newGroup != null && IsActive())
            newGroup.RegisterToggle(this);

        // If we are in a new group, and this toggle is on, notify group.
        // Note: Don't refer to m_Group here as it's not guaranteed to have been set.
        if (newGroup != null && isOn && IsActive())

这里是设置Toggle的ToggleGroup 在设置的时候有时候样根据当前Toggle的状态 通知到所有是当前ToggleGroup的Toggle进行状态改变

ToggleGroup

ToogleGroup 顾名思义是给Toggle打一个组 当当前Group下的某个Toggle状态改变时,组内其他Toggle也需要改变状态

public class ToggleGroup : UIBehaviour
{
    [SerializeField] private bool m_AllowSwitchOff = false;

    /// <summary>
    /// Is it allowed that no toggle is switched on?
    /// </summary>
    /// <remarks>
    /// 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.
    /// </remarks>
    public bool allowSwitchOff { get { return m_AllowSwitchOff; } set { m_AllowSwitchOff = value; } }

    protected List<Toggle> m_Toggles = new List<Toggle>();
    
    ...
}

m_Toggles 时记录有当前Group下的Toggle

allowSwitchOff | m_AllowSwitchOff 是否允许关闭所有Toggle。正常情况下一个m_Toggles 列表里 总是会有一个Toggle的状态为True 。但是有些时候也可能需要所有的都为Fasle


    /// <summary>
    /// 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.
    /// </summary>
    public void EnsureValidState()
    {
        if (!allowSwitchOff && !AnyTogglesOn() && m_Toggles.Count != 0)
        {
            m_Toggles[0].isOn = true;
            NotifyToggleOn(m_Toggles[0]);
        }

        IEnumerable<Toggle> activeToggles = ActiveToggles();

        if (activeToggles.Count() > 1)
        {
            Toggle firstActive = GetFirstActiveToggle();

            foreach (Toggle toggle in activeToggles)
            {
                if (toggle == firstActive)
                {
                    continue;
                }
                toggle.isOn = false;
            }
        }
    }

初始化状态 默认是将除第一个Toggle外 其他所有Toggle都置为False 。


    /// <summary>
    /// Notify the group that the given toggle is enabled.
    /// </summary>
    /// <param name="toggle">The toggle that got triggered on.</param>
    /// <param name="sendCallback">If other toggles should send onValueChanged.</param>
    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);
        }
    }

这个方法是将除了输入的Toggle之外所有的Toggle都关闭(isOn = false)

猜你喜欢

转载自blog.csdn.net/NippyLi/article/details/123302393
今日推荐