Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Unity UI UI system highlighting last clicked button problem, possible easy solution

Discussion in 'UGUI & TextMesh Pro' started by JuicyApe, Oct 5, 2018.

  1. JuicyApe

    JuicyApe

    Joined:
    Apr 1, 2017
    Posts:
    17
    So anyone whos being using the ui with a mouse has probably encountered the problem detailed here. https://answers.unity.com/questions/854724/unity-46-ui-button-highlight-color-staying-after-b.html
    https://stackoverflow.com/questions...tion-state-behaviour-it-remains-highlighted-a
    You set up a series of buttons, maybe for a main menu and the highlighting works fine the clicking works fine but theres a strange quirk with the ui system.
    1.png
    Once clicked a button stays highlighted even when the mouse is moved away, or more accurately it stays selected as it is the last button pressed. This looks and feels like a bug, it certainly isnt how we expect a mouse based menu to work. Also because the ui system uses the same visual states for selections and highlighting you can end up with the pic below when highlighting a button after pressing one.
    2.png
    This is quite visually confusing! We probably dont want this as default behaviour, so what can we do about it?
    Well the most common solution proposed in the many many threads on this topic is to simply disable navigation on each button. This works for a purely mouse driven ui as buttons are no longer selected when pressed, but what if we're designing ui that can take input from arrow keys or a controller as well as a mouse? Navigation is essential for such a system.

    Alternative solutions proposed are writing a custom script that will listen for the mouse cursor to leave a selected button and manually deselect it. These tend to be a chore and involve you putting a lot of custom scripts on each ui component in your scene. Instead all we really need to know is if the user is trying to use the mouse or not, if so we're free to clear the current selections. A simple script like the one below can be attached to any menu you have suffering from this problem and when the menu is enabled selection will be cleared on any mouse movement.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.EventSystems;
    5.  
    6. public class UISelectionClearer : MonoBehaviour
    7. {
    8.     void Update()
    9.     {
    10.         //if mouse has moved clear selection
    11.         if ((Input.GetAxis("Mouse X") != 0) || (Input.GetAxis("Mouse Y") != 0)) {
    12.             Debug.Log("Mouse Moved");
    13.             EventSystem.current.SetSelectedGameObject(null);
    14.         }
    15.     }
    16.  
    17. }
    If any veterans see a problem with this solution please tell me. Also if any unity devs are seeing this can we please have different visual states for selection and highlighting? I know its been mentioned in the past but it would solve a lot of these hacky solutions people end up using for a fairly simple problem
     
    bobbaluba likes this.
  2. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @JuicyApe

    Not a veteran, but your script would run each frame as it's in update.

    An idea - but I'm not sure about this (since I haven't tested such idea fully);

    You could create a subclass for button. In it, you would check for PointerExit event (using PointerExitHandler), then clear the current selection on Pointer Exit.

    This way you don't need constant update based check, and you are not clearing selection for no reason just because user moved mouse pointer.

    You just have to add your version of Button when you want this behavior.
     
  3. JuicyApe

    JuicyApe

    Joined:
    Apr 1, 2017
    Posts:
    17
    Yeah that was one of the suggestions that kept coming up, either extending the button class or adding custom script to each button. The issue with this is its a little awkward to maintain, every button you ever make has to have this added and if one has it missing it produces inconsistent ui.

    It also doesnt make much sense structure wise to control an overall ui behaviour in a non centralised location, why should individual elements be in control of a general behaviour?
    keeping it central lets you turn the behaviour on or off easily

    The constant update is a little annoying, a mouse moved event would be better but as far as i know none exist for runtime. Honestly though it would only be running while the ui is enabled and im not sure 100 seperate event listeners would be anymore effecient than a single lightweight update funtion anyway.
     
  4. JuicyApe

    JuicyApe

    Joined:
    Apr 1, 2017
    Posts:
    17
    So i've been playing around a bit with this and to make a ui that handles controllers and mouse you really need to make sure you provide a way to re-select the ui when controller motion is detected rather than just deselecting it outright.

    Having some sort of control type listener is good, that listens to input events to work out if the player wants to use mouse, arrow keys or a controller and can switch between them on the fly.

    If the mouse is used then the cursor should be shown and all current selections cleared. If arrow keys or a controller are used then navigation is needed, so an entry point on the ui should be selected and the cursor hidden. (for your purposes you might want to use the mouse with the keyboard keys depending on ur game.)

    Now the type of controls the player is using is a constant between scenes, so rather than attach this object to each ui menu it may make sense to have it as a persistent (dontDestroyOnLoad) object that is initialised when first starting the game up. This way it wouldn't directly handle what to do with the ui on control switching but rather would dispatch events that each different ui could listen to when the controls used change. This would also let you swap the buttons you tell the player to press based on what controls they're using. The control listener object may do one thing by itself, and thats hiding and showing the cursor (so that it doesn't get unhidden between scene loads.)