天天看點

UGUI——ToggleGroup我的notion筆記邏輯優化點附錄

我的notion筆記

邏輯

直接繼承自UIBehaviour

  1. 提供了RegisterToggle接口,Toggle組在SetToggleGroup中調用,将自身加入m_Toggles
public void RegisterToggle(Toggle toggle)
{
    if (!m_Toggles.Contains(toggle))
        m_Toggles.Add(toggle);

    if (!allowSwitchOff && !AnyTogglesOn())
    {
        toggle.isOn = true;
        NotifyToggleOn(toggle);
    }
}

           
  1. allowSwitchOff 用于控制再次點選是否關閉。如果是false的話,說明始終有一個是on狀态,在toggle有變化時會進行檢查
  2. UnregisterToggle接口,RegisterToggle的反向操作,也會有2的檢查
public void UnregisterToggle(Toggle toggle)
{
    if (m_Toggles.Contains(toggle))
        m_Toggles.Remove(toggle);

    if (!allowSwitchOff && !AnyTogglesOn() && m_Toggles.Count != 0)
    {
        m_Toggles[0].isOn = true;
        NotifyToggleOn(m_Toggles[0]);
    }
}

           
  1. NotifyToggleOn接口,當toggle激活時調用。在toggle的isOn被設定時,會判斷toggle是否有group,調用group的NotifyToggleOn接口。将除了指定的toggle外的toggle關閉。
/// <summary>
/// Notify the group that the given toggle is enabled.
/// </summary>
/// <param name="toggle">The toggle that got triggered on</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);
    }
}

           
  1. Toggle的set,設定不一樣的值時觸發,如果有組的話,當設定為true或者組内沒有toggle被激活且必須有一個toggle被激活時觸發,調用組的NotifyToggleOn接口。 如果需要sendCallback時,調用

    public ToggleEvent onValueChanged = new ToggleEvent();

    接口觸發回調。
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 && 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);
    }
}

           

優化點

  1. List<Toggle> m_Toggles

    申明為List,變長數組(類似C++的vector),而注冊/反注冊接口使用了Contain、Remove,除此之外還有些查找操作,更适合使用map/hashmap/set。
  2. AnyTogglesOn會在toggle初始化時和toggle設定值時被頻繁調用,可以将結果緩存起來或在改變時動态記錄,不用每次周遊。
  3. ActiveToggles 視項目調用頻繁程度,可做2的優化

附錄

C# List 源碼Contains:

// Contains returns true if the specified element is in the List.
// It does a linear, O(n) search.  Equality is determined by calling
// item.Equals().
//
public bool Contains(T item) {
    if ((Object) item == null) {
        for(int i=0; i<_size; i++)
            if ((Object) _items[i] == null)
                return true;
        return false;
    }
    else {
        EqualityComparer<T> c = EqualityComparer<T>.Default;
        for(int i=0; i<_size; i++) {
            if (c.Equals(_items[i], item)) return true;
        }
        return false;
    }
}

           

Remove: 這個用在這裡更廢,先周遊找到item對應下标,再從數組中移除(需要将index後的元素複制到前面)

// Removes the element at the given index. The size of the list is
// decreased by one.
// 
public bool Remove(T item) {
    int index = IndexOf(item);
    if (index >= 0) {
        RemoveAt(index);
        return true;
    }

    return false;
}