Search Unity

Question How do I change the styling of a Label on a Custom Control implemented from a BaseField?

Discussion in 'UI Toolkit' started by MokeyBrat70, May 26, 2023.

  1. MokeyBrat70

    MokeyBrat70

    Joined:
    Mar 15, 2014
    Posts:
    3
    I am trying to create a custom slider to use in my project at runtime in a HUD that is always on the screen, because the styling options for the default slider are very limited. After many attempts on my own, google searches, Documentation/Manual reviews, etc...I found a tutorial (Official Unity -- I prefer those) on building a custom toggle switch, because it was closest to the slider (might be a bad assumption, but it has helped me understand the process of creating a custom control in C#). Link to the tutorial.

    So in the hierarchy in the UI Builder, the control has the following Heirarchy:

    SlideToggle (This is the custom control based on BaseField<bool>)
    Label
    VisualElement (the toggle field which contains the knob)
    VisualElement (the knob)​

    upload_2023-5-26_7-42-50.png

    The tutorial took me through the process of building the custom uss file and the C# class for the new SlideToggle. It seems trivial to access the VisualElements and make changes to their classes.

    However, when I try to access the Label, to change the margins, padding, size, etc. with a custom class, for the life of me, none of the queries I have tried work.

    In C# this works perfect to change the styling of the Visual Elements:

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.UIElements;
    4. namespace MyUILibrary
    5. {
    6.     // Derives from BaseField<bool> base class. Represents a container for its input part.
    7.     public class SlideToggle : BaseField<bool>
    8.     {
    9.         public new class UxmlFactory : UxmlFactory<SlideToggle, UxmlTraits> { }
    10.         public new class UxmlTraits : BaseFieldTraits<bool, UxmlBoolAttributeDescription> { }
    11.         // In the spirit of the BEM standard, the SlideToggle has its own block class and two element classes. It also
    12.         // has a class that represents the enabled state of the toggle.
    13.         public static readonly new string ussClassName = "slide-toggle";
    14.         public static readonly new string inputUssClassName = "slide-toggle__input";
    15.         public static readonly string inputKnobUssClassName = "slide-toggle__input-knob";
    16.         public static readonly string inputKnobCheckedUssClassName = "slide-toggle__input--checked";
    17.         public static readonly new string labelUssClassName = "slide-toggle__label";
    18.         public static readonly string baseFieldLabelClassName = "unity-base-field__label";
    19.         VisualElement m_Input;
    20.         VisualElement m_Knob;
    21.         VisualElement m_Label;
    22.         // Custom controls need a default constructor.  This default constructor calls the other constructor in this class.
    23.         public SlideToggle() : this(null) { }
    24.         // This constructor allows user to set the contents of the label
    25.         public SlideToggle(string label) : base(label, null)
    26.         {
    27.             // Style the control overall
    28.             AddToClassList(ussClassName);
    29.            
    30.             // Get the BaseField's visual input element and use it as the background of the slide.
    31.             m_Input = this.Q(className: BaseField<bool>.inputUssClassName);
    32.             m_Input.AddToClassList(inputUssClassName);
    33.            
    34.             Add(m_Input);
    35.             //For the life of me I cannot find a query which will access the Label
    36.             m_Label = this.Q(className: BaseField<bool>.labelUssClassName);
    37.             if(m_Label is null)
    38.             {
    39.                 Debug.Log("m_Label was not assigned.");
    40.             }
    41.             else
    42.             {
    43.                 Debug.Log($"m_Label = {m_Label}");
    44.             }
    45.             // Create a "knob" child element for the background to represent the actual slide of the toggle.
    46.             m_Knob = new();
    47.             m_Knob.AddToClassList(inputKnobUssClassName);
    48.             m_Input.Add(m_Knob);
    49.  
    50. // The code continues from here to implement the functions and callbacks
    51.  
    However, as noted int the code comment at the point in the code where I try to find the Label so I can add my custom styling, I cannot find a query that works.

    The one in the code seems the most intuitive, but I have also tried:

    m_Label = this.Q<Label>();

    m_Label = this.Q(className: ussClassName).Children().GetEnumerator().Current;

    m_Label = this.Q(className: ussClassName).Children().First();

    This last one won't even compile even though is seems to be correct according to this documentation.

    I have tried others, but I cannot remember them.

    NOTE: I included the if - then block because if you try to do anything with m_Label when it is null, the console logs an endless loop of NullReference errors. (I reported that bug separately).

    Please let me know if I am simply overlooking something or if there is a reason I cannot access the label to change it's styling.
     
  2. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    Base Field only adds the label element to its hierarchy when it's label property is not null or empty. You can also access the label element with the labelElement property, and that works even when the label is empty.

    An alternative is to use a child selector to style the field's label in USS:
    .my-field > .unity-base-field__label
     
    MokeyBrat70 and cpalma-unity like this.
  3. MokeyBrat70

    MokeyBrat70

    Joined:
    Mar 15, 2014
    Posts:
    3
    Code (CSharp):
    1. m_Label = this.labelElement;
    Worked! I don't know why I locked up on this so long, but thank your your prompt and proper response and your link to the documentation.