Search Unity

  1. Full schedule for #UniteBerlin is now available! Featuring talks on our roadmap, hands-on labs and much more! Check it out!
    Dismiss Notice
  2. Unity 2018.1 has arrived! Read about it here
    Dismiss Notice
  3. Scriptable Render Pipeline improvements, Texture Mipmap Streaming, and more! Check out what we have in store for you in the 2018.2 Beta.
    Dismiss Notice
  4. ARCore is out of developer preview! Read about it here.
    Dismiss Notice
  5. Magic Leap’s Lumin SDK Technical Preview for Unity lets you get started creating content for Magic Leap One™. Find more information on our blog!
    Dismiss Notice
  6. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

non-interactable UI element (e.g. button) not skipped by navigation

Discussion in 'Unity UI & TextMesh Pro' started by garv3, Dec 13, 2014.

  1. garv3


    Dec 30, 2012
    If I set a UI element (e.g. a button) as not interactable, I would expect it to be skipped by the navigation events (up, down, left, right), but it can still be selected. It won't change the Transition graphic, but it is not skipped and even its OnSelect is triggered.
    Is this intended or a bug?
  2. hoesterey


    Mar 19, 2010
    Seams intended. I could see wanting the user see info on a "Locked' button. E.g. A level that is not selectable yet. Though an option would be nice.
  3. garv3


    Dec 30, 2012
    Then maybe there should at least be an animation option (e.g. color tint, image...) to set for a selected non-interactive element. Right now the user can not see, if the element is selected.
    If I have three elements for example:
    left: interactableElement - center: NONinteractableElement - right: NONinteractableElement
    then there is a problem. If the left element is selected by default and the user navigates to the right, he can only see that the element is not selected any more, but he is unable to see which element is currently selected. If he now presses the "right arrow key" again, nothing changes visually but actually the right element is selected. What he would at least expect now is, that if he presses the "left arrow key", the left element should be selected again. But still nothing happens. Confusion is the result. This can not be the way it is meant to be...
  4. TechCor


    Apr 3, 2015
    This problem is really this old? Blah.

    There is no way around this problem if you can't use automatic mode. It should really pass through like automatic does.

    It's almost like no one uses controllers on menu screens with non-interactable buttons with Unity.

    Hey, I'm offline. Let me just gray out this "social" button between these other menu options.
    Wait, why is my highlight disappearing? Oh, it selected this button that the user obviously doesn't want to go to.

    I could maybe see being able to select it to bring up some kind of help popup, but one could just as easily fake the gray out by replacing the sprite. On the other hand, you practically have to replace the navigation system to get around this problem. I can't tell the non-interactable button to just pass through to the next, so I'd either have to write my own nav system on top of Unity's or have conditionals for every non-interactable button that handles each direction that I might want to pass through.

    This isn't even the only problem with the nav system. I've already had to write a special helper script to take care of a bunch of other poor design problems.
  5. karl_jones


    Unity Technologies

    May 5, 2015
  6. TechCor


    Apr 3, 2015
    Yes, I saw that feedback before posting and gave it a couple votes, but I'm surprised that no one else has mentioned it. Maybe they just work around it. Speaking of which, here is a workaround for anyone else having this issue. I still think this should be default behavior though (consistent with automatic mode).

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.UI;
    4. using UnityEngine.EventSystems;
    6. public class SkipNonInteractable : MonoBehaviour, ISelectHandler
    7. {
    8.    private Selectable m_Selectable;
    10.    // Use this for initialization
    11.    void Awake()
    12.    {
    13.      m_Selectable = GetComponent<Selectable>();
    14.    }
    16.    public void OnSelect(BaseEventData evData)
    17.    {
    18.      // Don't apply skipping unless we are not interactable.
    19.      if (m_Selectable.interactable) return;
    21.      // Check if the user navigated to this selectable.
    22.      if (Input.GetAxis("Horizontal") < 0)
    23.      {
    24.        Selectable select = m_Selectable.FindSelectableOnLeft();
    25.        if (select == null || !select.gameObject.activeInHierarchy)
    26.          select = m_Selectable.FindSelectableOnRight();
    27.        StartCoroutine(DelaySelect(select));
    28.      }
    29.      else if (Input.GetAxis("Horizontal") > 0)
    30.      {
    31.        Selectable select = m_Selectable.FindSelectableOnRight();
    32.        if (select == null || !select.gameObject.activeInHierarchy)
    33.          select = m_Selectable.FindSelectableOnLeft();
    34.        StartCoroutine(DelaySelect(select));
    35.      }
    36.      else if (Input.GetAxis("Vertical") < 0)
    37.      {
    38.        Selectable select = m_Selectable.FindSelectableOnDown();
    39.        if (select == null || !select.gameObject.activeInHierarchy)
    40.          select = m_Selectable.FindSelectableOnUp();
    41.        StartCoroutine(DelaySelect(select));
    42.      }
    43.      else if (Input.GetAxis("Vertical") > 0)
    44.      {
    45.        Selectable select = m_Selectable.FindSelectableOnUp();
    46.        if (select == null || !select.gameObject.activeInHierarchy)
    47.          select = m_Selectable.FindSelectableOnDown();
    48.        StartCoroutine(DelaySelect(select));
    49.      }
    50.    }
    52.    // Delay the select until the end of the frame.
    53.    // If we do not, the current object will be selected instead.
    54.    private IEnumerator DelaySelect(Selectable select)
    55.    {
    56.      yield return new WaitForEndOfFrame();
    58.      if (select != null || !select.gameObject.activeInHierarchy)
    59.        select.Select();
    60.      else
    61.        Debug.LogWarning("Please make sure your explicit navigation is configured correctly.");
    62.    }
    63. }
    Add this script to any buttons that need to be skipped when not interactable.

    Note: This does not stop event propagation. Any other scripts using OnSelect() need to check for interactable.

    Code now handles noninteractable buttons that can't pass through (sends it back the other direction). Includes handling inactive objects.
    Last edited: Feb 23, 2016
    tomtominc, Sigma266 and ben-maurin like this.
  7. LightStriker


    Aug 3, 2013
    That bug is so God damn dumb. How is that even a thing? (Almost 2 years later)
  8. YVanhoutte


    Mar 5, 2018
    Good to see I'm not the only one stumbling on this.
    I worked around it myself since I have dynamic content for my UI (in which case thanks to indentation the automatic navigation was giving very inconsistent results), but to me this once again highlights the importance of having a separation of highlighting and selecting objects in the eventsystem.