Coder
Coder

Reputation: 529

How to Get UI button to Stay in a Pressed State in Unity 3D

In Unity 3D, when you select a button, it will stay pressed until you click outside the button and basically goes back to its Normal Color. The problem is, I want the button to stay pressed (color-wise) when I click outside the button or scene. Does anyone know how to keep a button pressed or "selected" after clicking it?

Upvotes: 1

Views: 13824

Answers (5)

Lou Garczynski
Lou Garczynski

Reputation: 635

You can use reflection to access protected Selectable methods

using System.Reflection;
using UnityEngine.UI;

public static class UIExtensions
{
    private abstract class Accessor : Selectable
    {
        public const int SelectedEnumValue = (int)SelectionState.Selected;
    }

    private static readonly MethodInfo DoStateTransition = typeof(Selectable).GetMethod("DoStateTransition", BindingFlags.Instance | BindingFlags.NonPublic);
    private static readonly object[] ArgArray = { Accessor.SelectedEnumValue, false };

    public static void SetSelected(this Selectable button)
    {
        DoStateTransition.Invoke(button, ArgArray);
    }
}

Add this class to your project, and you can just call SetSelected on any button or toggle you want. It will not affect the button logic, only the display state.

Upvotes: 0

Jen Cleary
Jen Cleary

Reputation: 1

I wanted something really simple, so I just changed the Image of the button Game Object on the click and then to an unselected image if it's clicked again.

  1. Leave the button in the Inspector as Interactable

  2. Change the button Transition in the Inspector to 'Color Tint' and make the highlight, selected and pressed all white

  3. Load your Sprites (make sure they're directly in the root of the Resources folder and not buried in a directory or they won't load)

    Sprite selected = Resources.Load("ButtonSelected", typeof(Sprite)) as Sprite;
    Sprite unselect = Resources.Load("SelectButton", typeof(Sprite)) as Sprite;
    
  4. Get the object of your button

    GameObject SB1 = GameObject.FindWithTag("SelectButton1");
    
  5. On the button click change the sprite (the Image of your GameObject) in your button press function

    if (GameManager.card1Selected == true)
    {
        SB1.GetComponent<Image>().sprite = selected;         
    }
    else
    {
        SB1.GetComponent<Image>().sprite = unselect;           
    }
    

Upvotes: 0

Akrima Huzaifa
Akrima Huzaifa

Reputation: 26

Here is the C# script using delegate that'll (toggle between buttons) set clicked button to "on/pressed" (custom) colour and change the other button(s) with this script attached to them to deselect colour, Copy & paste solution(attach this script to buttons you want to toggle between):

using TMPro;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// Functionality: Control UI Button clicks selected colour
/// Author: Akrima Huzaifa
/// Date Created: 1st-December-2022
/// </summary>

public class BtnClickHandler : MonoBehaviour
{
 public delegate void OnBtnClick(BtnClickHandler obj);
 public static event OnBtnClick onBtnClick;
 public Button poleBtn;
 public Image poleImage;

 private void Awake()
 {
     if (GetComponent<Button>())
     {
         poleBtn = GetComponent<Button>();
         poleImage = GetComponent<Image>();
         poleBtn.onClick.AddListener(delegate { OnBtnClick(); });
     }
 }

 private void OnEnable()
 {
     onBtnClick += SelectDeselectBtn;
 }

 private void OnDisable()
 {
     onBtnClick -= SelectDeselectBtn;
 }

 public void SelectDeselectBtn(BtnClickHandler obj)
 {
     if (obj == this)
     {
         OnClick_ObjButtonSelected();
     }
     else
     {
         DeselectBtn();
     }
 }

 public void OnBtnClick()
 {
     BtnClickHandler.onBtnClick.Invoke(this);
 }

 //---For UI---
 public void OnClick_ObjButtonSelected()
 {
     if (!poleImage.fillCenter)
     {
         print("if color");
         poleImage.fillCenter = true;
         poleImage.color = new Color32(230, 230, 230, 255);
         poleImage.transform.GetComponentInChildren<TextMeshProUGUI>().color = new Color32(255, 115, 0, 255);
     }
     else
     {
         DeselectBtn();
     }
 }

 public void DeselectBtn()
 {
     print("else color");
     poleImage.fillCenter = false;
     poleImage.color = new Color32(178, 178, 178, 255);
     poleImage.transform.GetComponentInChildren<TextMeshProUGUI>().color = new Color32(255, 255, 255, 255);
 }
}

Upvotes: 0

Jianing Zhuang
Jianing Zhuang

Reputation: 1

public class Button_Stay_Pressed : MonoBehaviour
{
    private Button btn;

    [SerializeField]
    private Sprite normal_sprite;
    [SerializeField]
    private Sprite pressed_sprite;

    void Awake()
    {
        btn = gameObject.GetComponent<Button>();
        btn.image.sprite = normal_sprite;
        btn.onClick.AddListener(TaskOnClick);
    }

    void TaskOnClick()
    {
        btn.image.sprite = pressed_sprite;
    }
}

Upvotes: 0

AlexAR
AlexAR

Reputation: 1324

You can use Unity UI Toggle (as said by Muhammad). Change the design to remove the checkmark and make it looking like a button. With this component you have the state 'isOn' that you can use and change the color when selected for example.

Upvotes: 2

Related Questions