I have a standard UI Button within a panel, and a different color for each of the transition states, to make it easy to identify which state it is in. Each state works as intended, except after I click on a button, the state transitions from the ‘Pressed Color’ back to the ‘Highlighted Color’.
Unfortunately, it persists in this state even after moving the mouse off of the button. Clicking anywhere else within game sets the button back to the ‘Normal Color’ state.
I have adjusted different properties, but there really aren’t that many related properties on a button that would affect this, so I am having trouble with it.
All you need to do is remove the currently selected object from the event system, since technically, the button is then the ‘selected’ object after clicking it. Its like the windows ‘focus’ rect around the current field.
using UnityEngine.EventSystems;
EventSystem.current.SetSelectedGameObject(null);
If you pop that into your buttonpressed script/method, then it will remove the selection and colour immediately.
In my case, setting the navigation to NONE didn’t work.
The solution is to disable and re enable the button component and if you have animations, trigger the “Normal” animation transition.
Wouldn’t this be solved if they include a Hover state?
This will give you full control, you could make the state different from the Highlight state and users do not get confused with two highlighted elements and you can still keep using the keyboard/joystick navigation system.
In this case you could also have the choice to decide whether the button should be different in a hover state or stay the same if you do not want that behavior!
I think most importantly it should work correctly for one input at a time. The navigation features are especially important for those with disabilities using alternate controls (via keyboard interface typically). So making a custom user experience that involves a combo of mouse and keyboard at the same time seems counter-productive to me. This is exactly why I cringe whenever someone suggests the “fix” is to turn navigation off entirely.
Right now though, the way the navigation and hover uses the same highlight just causes confusion in most cases.
For your original suggestion, it could be achieved using an Event Trigger with PointerEnter and PointerExit and apply a temporary overrideSprite as a “hover”.
I’ve got an answer that is even simpler and more direct than EventSystem.current.SetSelectedGameObject(null) that worked for me.
using UnityEngine;
using UnityEngine.EventSystems;
public class DemoPointerOffClass : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
private Button _btn;
private void Awake()
{
_btn = this.gameObject.GetComponent<Button>();
}
public void OnPointerEnter(PointerEventData eventData)
{
_btn.OnSelect(eventData);
}
public void OnPointerExit(PointerEventData eventData)
{
_btn.OnDeselect(eventData);
}
}
Put this script on the same object that you have your button on. I do NOT understand why the Button component does not called Button.OnDeselect by default when a pointer exits its hitbox, but alas.
So, I was having a similar issue, but I was able to solve it without turning off navigation as I wanted the UI to work both with Controllers/Keyboard (buttons) and Mouse Pointer.
Anyways, the way I solved this is to do a SendMessage(“OnPointerExit”, PointerEventData) when I detect if someone has pressed a keyboard button or moved the analog stick/dpad.
Hopefully this answer will help someone out.
Simple Code Example:
private void OnGUI()
{
//this gives us constant information on what is happening
mouseData = EventSystem.current.GetComponent<StandaloneInputModuleCustom>().GetLastPointerEventDataPublic(-1);
string verticalAxisName = EventSystem.current.GetComponent<StandaloneInputModuleCustom>().verticalAxis;
if (mouseData.IsPointerMoving())
{
if(mouseData.pointerEnter != null)
EventSystem.current.SetSelectedGameObject(mouseData.pointerEnter);
}
//check to see if input has been pressed that isn't the mouse and turn off mouse logic
if (Input.GetAxis(verticalAxisName) != 0 || Input.GetButtonDown(verticalAxisName))
{
mouseData.selectedObject.SendMessage("OnPointerExit", mouseData);
}
}
I believe you can understand the rest, such as initiating which buttons to be pressed at startup, checking if pressed using if(), and then setting it to be pressed after user had clicked the button.
Unity 2018… bug still exists. My solution, add the following script to each button.
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;// Required when using Event data.
/// <summary>
/// This script addresses the Unity bug that buttons stay highlighted after you select them
/// and then move off the button.
/// This results in two buttons being active at the same time.
/// https://forum.unity.com/threads/clicking-a-button-leaves-it-in-mouseover-state.285167/
/// https://answers.unity.com/questions/854724/unity-46-ui-button-highlight-color-staying-after-b.html
/// https://docs.unity3d.com/ScriptReference/UI.Selectable.OnPointerExit.html
/// My solution was based off a couple of answers together.
/// </summary>
public class ARButtonHighlightfix : MonoBehaviour, IPointerExitHandler// required interface when using the OnPointerExit method. {
{
//Do this when the cursor exits the rect area of this selectable UI object.
public void OnPointerExit(PointerEventData eventData)
{
//Debug.Log("The cursor exited the selectable UI element.");
EventSystem.current.SetSelectedGameObject(null);
}
}
If you don’t need controller support, setting navigation to “None” is fine UNLESS you instantiate buttons (use a prefab) and set up an “onClick” (“myButton.onClick.AddListener(ClickMethod)”) for them at runtime because then “EventSystem.current.currentSelectedGameObject.GetComponent()” just throws an exception!
In this case bilalseh’s solution works perfectly:
Just add EventSystem.current.SetSelectedGameObject(null);
directly AFTER getting the currently selected button from the event system. Since it’s in an “onClick” method, you don’t even have to use “Update()” and also also don’t need “Input.GetMouseButtonUp(0)”;
Unfortunately there’s a big BUT: No matter what the navigation is set to, as soon as you use a touchscreen, the buttons don’t properly reset, even if you reset the EventSystem by hand. Still trying to get that fixed, so if anyone has a suggestion for that I would be grateful!