Toggle the background image of a button

Maybe my search strings are not the best but I can’t find a way to change the image of a button after I clicked it. The “button:active” state changes the icon if I want it to but it reverts to the original one after the mouse click. I need to change it permanently until the button is clicked again (music mute/unmute button).
I got the button in a C# script and there’s a button.style.backgroundImage I can use but unfortunately I don’t know how and nothing I’ve tried worked.
Also, there are “checked” and “selected” states in the UI Builder but they don’t seem to work. (Update: apparently selected is not used and checked only works for toggles but I can’t use a toggle instead of a button because I can’t remove the checkbox from it).
I feel like there’s something really easy but I can’t figure it out. I’d appreciate any help. Thanks.

Update:
I’ve tried this and it removes the existing image for the button but it doesn’t add the new one for some reason:
var buttonIcon = musicButton.Q(className: “BotMenu-button”);
var iconPath = “/Assets/UI/Textures/disabled.png”;
var iconAsset = Resources.Load(iconPath);
buttonIcon.style.backgroundImage = iconAsset;

I made my own “button” (more like a toggle) in c#.

My tip: Ignore everything about UI Builder. It’s half implemented and half broken. When you need a tool, you cant work with half of one.

C# side however is near feature complete, or at least isn’t noticably broken. I haven’t run into any strange problems in my prototyping. However, there is a loooooot of boilerplate.

Here’s my implementation of a button. It requires 3 VisualElements, two of which have sprites and one of them is the container.

// These two buttons swap position in hierarchy in order to be shown or not.
// Don't know if more efficient than just changing sprites on click. Someday I'll be able to profile it.
new VisualElement()
    .SetVariable(out var buttonSwapping)
    .Set(transform: new Vector2(100, 100)) // 100x100 px square.
    .SetParent(RootElement);
 
// Off.
new VisualElement()
    .SetVariable(out Off)
    .Set(_class: "FillContainer") // Fill container is a USS class See below.
    .SetSprite(OffButton) // Off button sprite.
    .SetParent(buttonSwapping);
 
// On. Default state.
new VisualElement()
    .SetVariable(out On)
    .Set(_class: "FillContainer")
    .SetSprite(OnButton) // On button sprite, overlayed and completely covers off button sprite.
    .SetParent(buttonSwapping);
 
// Default behavior.
On.RegisterCallback<MouseUpEvent>(evt =>
{
    // Makes the button "disappear". There's only two elements in this hierarchy so it just swaps with OffButton.
    On.SendToBack();
    evt.StopPropagation(); // Prevents the button behind the clicked one from reacting.
});
Off.RegisterCallback<MouseUpEvent>(evt =>
{
    Off.SendToBack();
    evt.StopPropagation();
});

The .Set() functions are my own custom extensions to simplify and eliminate the boilerplate on changing the styles.

As for the Fill Container class:

.FillContainer
{
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
}

This is of course the “default” behavior of the button. Further on in the loading process, I’ve coded in specialized reactions to the buttons being clicked by just adding more .RegisterCallback<>()'s.

1 Like

Thanks Kmsxkuse. I didn’t intend to put any effort into the UI at this stage in the development (and I’ve already been on it for a day with mixed results). I just wanted to add a few buttons. A button that stays pressed seemed like a pretty basic requirement.

1 Like

If you’re just prototyping, then I recommend using the gameobjects based UI.

My main project is using gameobjects UI and I was playing around with UI Toolkit as preparation for a conversion.

From my ehhh week or so of trial and error, I get the impression that UI Builder is completely worthless and UI Toolkit as magical (one draw call to rule them all) but very work intensive to set up.

Maybe in a year or so, Unity will flesh out Toolkit and Builder to be on par with UGUI in terms of ease of use. Probably not, seeing how DOTS is going.

1 Like