Search Unity

Make button style 'selected' or 'toggled' through script

Discussion in 'UI Toolkit' started by alexanderameye, Feb 16, 2020.

  1. alexanderameye

    alexanderameye

    Joined:
    Nov 27, 2013
    Posts:
    1,383
    I have a toolbar like this with several sections.

    upload_2020-2-16_20-29-43.png

    I want the active section to be a different color when clicked on. Is there a way to change the button through script to some kind of 'selected' or 'toggled' state that will change its color? I want it to look native and work for both light and dark theme.
     
  2. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,188
    Use the ToolbarToggle or regular Toggle and set it's value property to true or false instead of a button.
     
    alexanderameye likes this.
  3. alexanderameye

    alexanderameye

    Joined:
    Nov 27, 2013
    Posts:
    1,383
    And how can I check if the button was clicked?

    Before for my buttons I used

    Button.clickable.clickedWithEventInfo += Function;

    but the Toggle does not seem to have the clickable property.
     
  4. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,188
    Like this:

    Code (CSharp):
    1. Toggle toggle = new Toggle("Option A");
    2. toggle.value = true; // Set toggle active in script.
    3. toggle.RegisterValueChangedCallback(evt =>
    4. {
    5.     Debug.Log("Toggle was changed to value: " + evt.newValue);
    6. });
     
  5. VOTRUBEC

    VOTRUBEC

    Joined:
    Dec 17, 2014
    Posts:
    106
    These are what I use:

    Code (CSharp):
    1. yourToggle.RegisterValueChangedCallback<bool> ( x => Function() );
    2. yourButton.RegisterCallback<MouseUpEvent> ( x => Function ( ) );
     
  6. alexanderameye

    alexanderameye

    Joined:
    Nov 27, 2013
    Posts:
    1,383
    Yeah but this callback is triggered whenever the value changes right? Not when I click on the toggle?

    I want the sections to be selected one by one, how do I achieve this?

    So right now I have this code.

    Code (CSharp):
    1.   supportToggle.RegisterValueChangedCallback(evt =>
    2.             {
    3.                 aboutToggle.value = false;
    4.                 acknowledgementsToggle.value = false;
    5.                 detectIssuesToggle.value = false;
    6.             });
    7.  
    8.             aboutToggle.RegisterValueChangedCallback(evt =>
    9.            {
    10.                supportToggle.value = false;
    11.                acknowledgementsToggle.value = false;
    12.                detectIssuesToggle.value = false;
    13.            });
    14.  
    15.             acknowledgementsToggle.RegisterValueChangedCallback(evt =>
    16.            {
    17.                supportToggle.value = false;
    18.                aboutToggle.value = false;
    19.                detectIssuesToggle.value = false;
    20.            });
    21.  
    22.             detectIssuesToggle.RegisterValueChangedCallback(evt =>
    23.            {
    24.                supportToggle.value = false;
    25.                aboutToggle.value = false;
    26.                acknowledgementsToggle.value = false;
    27.            });
    Because let's say I press the support toggle, I want the button to be toggled, and the rest to be off, so I set the values to 'false', but that triggers the other callbacks since the callback is simply for a value change, and it gets stuck...
     
    Last edited: Feb 17, 2020
  7. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,188
    What you're describing sounds like "radio buttons". I believe this would be a nice use-case for SetValueWithoutNotify:

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using UnityEngine.UIElements;
    4.  
    5. public class MyWindow : EditorWindow
    6. {
    7.     [MenuItem("Window/MyWindow")]
    8.     private static void ShowWindow()
    9.     {
    10.         GetWindow<MyWindow>("MyWindow");
    11.     }
    12.  
    13.     private Toggle[] radioButtons;
    14.  
    15.     private void OnEnable()
    16.     {
    17.         radioButtons = new Toggle[]
    18.         {
    19.             new Toggle("Option A") { name = "A" },
    20.             new Toggle("Option B") { name = "B" },
    21.             new Toggle("Option C") { name = "C" },
    22.         };
    23.  
    24.         for (int i = 0; i < radioButtons.Length; i++)
    25.         {
    26.             radioButtons[i].RegisterValueChangedCallback(OnToggleChanged);
    27.             rootVisualElement.Add(radioButtons[i]);
    28.         }
    29.     }
    30.  
    31.     private void OnToggleChanged(ChangeEvent<bool> evt)
    32.     {
    33.         // Turn off all other toggles except the one that is currently active.
    34.         for (int i = 0; i < radioButtons.Length; i++)
    35.         {
    36.             if (radioButtons[i] != evt.target)
    37.                 radioButtons[i].SetValueWithoutNotify(false);
    38.         }
    39.  
    40.         Debug.Log("Now active: " + ((VisualElement)evt.target).name);
    41.     }
    42. }
    43.  
    When one of the toggles changes, you set the value of all other toggles, but without sending any further changed events.
     
    FuguFirecracker and JoNax97 like this.
  8. FuguFirecracker

    FuguFirecracker

    Joined:
    Sep 20, 2011
    Posts:
    419
    I may be over-thinking this ( over-engineering ) ; Here's my solution :

    Code (CSharp):
    1.  
    2. public class ToggleGroup
    3. {
    4.     private readonly ToolbarToggle[] _toggles = new ToolbarToggle[2];
    5.  
    6.     public void SetToggle(ToolbarToggle tbt)
    7.     {
    8.         if (_toggles[0] == tbt)
    9.         {
    10.             tbt.SetValueWithoutNotify(true);
    11.             return;
    12.         }
    13.  
    14.         _toggles[0] = tbt;
    15.         _toggles[1]?.SetValueWithoutNotify(false);
    16.         _toggles[1] = _toggles[0];
    17.     }
    18. }
    19.  
    And call with :
    Code (CSharp):
    1.  
    2. private void Callback(ChangeEvent<bool> evt)
    3. {
    4.     _toggleGroup.SetToggle(evt.target as ToolbarToggle);
    5. }
    6.  
    Basically:Turn this one on; Turn that other one off.

    Despite only keeping track of 2 toggle buttons, it works for any number.
    I realized that if someone gave a quick glance, one might think it was just a 2 toggle solution lol.