Cómo ocultar los botones virtuales en Android / LibGDX

Introducción

Cuando creamos juegos para Android con LibGDX, normalmente querremos que nuestra aplicación ocupe toda la pantalla. Si el terminal donde ejecutamos la aplicación tiene botones virtuales en pantalla para las acciones Android (Home, Back, Menu, …) en lugar de botones físicos, veremos que nuestro juego no se ejecuta realmente a pantalla completa, ya que los botones Android permanecen en la pantalla mientras nuestro juego se ejecuta.

Utilizando el modo de ventana inmersivo, introducido en Android 4.4 KitKat (API 19), conseguiremos ejecutar nuestro juego a pantalla completa real, ocultando los botones virtuales de Android en caso de que existan.

Usar el modo de ventana inmersivo

Al generar el proyecto con LibGDX, el subproyecto Android contiene la clase AndroidLauncher, desde la que se configura cómo se ejecutará nuestro juego en estos dispositivos. Por defecto, en el método onCreate() se utiliza el siguiente fragmento de código para mostrar la aplicación a pantalla completa:

// Do the stuff that initialize() would do for you
 requestWindowFeature(Window.FEATURE_NO_TITLE);
 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);

El código anterior muestra la aplicación a pantalla completa, pero esto no es suficiente para ocultar los botones virtuales en caso de que existan. Para conseguirlo, hemos de utilizar el modo inmersivo de pantalla completa. De esta forma se ocultan los botones virtuales, barras de navegación, etc., y volverán a aparecer si hacemos un deslizamiento similar al que hacemos para desplegar las notificaciones. Existen dos variantes para el modo de ventana inmersivo:

  • View.SYSTEM_UI_FLAG_IMMERSIVE: Con esta opción, desaparecen todos los controles, barra de navegación, etc. de la pantalla. Cuando se vuelvan a mostrar, permanecerán en la pantalla a menos que volviéramos a ocultarlos explícitamente.
  • View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY: Igualmente desaparecen todos los controles, barra de navegación, etc. de la pantalla. Pero en esto caso, cuando los hacemos aparecer, se muestran de forma translúcida y, pasados unos segundos, se ocultan automáticamente. Personalmente, esta opción me parece más recomendable para nuestros proyectos.

El modo de ventana inmersivo fue un cambio introducido en el API 19 (Android 4.4 KitKat), por lo que sólo podremos usarlo a partir de esta versión. Si nuestro proyecto está configurado para versiones anteriores de API (atributo android:minSdkVersion del archivo AndroidManifest.xml) e intentamos hacerlo, obtendremos un error. Para solucionarlo crearemos un método encargado de establecer el modo inmersivo y este método estará anotado con @TargetApi(19), de forma que al comprobar los errores del proyecto, se tendrá en cuenta que ese método sólo será usado a partir del la versión 19 del API. Llamaremos a este método, por ejemplo, hideVirtualButtons() y será tal que así:

@TargetApi(19)
private void hideVirtualButtons() {
    getWindow().getDecorView().setSystemUiVisibility(
              View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
            | View.SYSTEM_UI_FLAG_FULLSCREEN
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}

Usando @TargetApi(19) hacemos que se tenga en cuenta en la comprobación de errores, pero no impide que el código se ejecute. Si se invoca este método en un dispositivo con una versión de android anterior al API 19, se producirá un error de ejecución. Con el siguiente código controlaremos que sólo se utiliza en dispositivos compatibles:

public void onCreate() {
    ....
    // In KITKAT (4.4) and next releases, hide the virtual buttons
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        hideVirtualButtons();
    }
}

Con esto, ya tendremos nuestro juego ejecutándose a pantalla completa real en dispositivos Android 4.4 y superiores. Sin embargo, aun queda una cuestión pendiente, pues si mientras estamos jugando cambiamos a otra aplicación (por ejemplo, la publicidad nos abre el navegador web) y después volvemos a nuestro juego, veremos que los botones virtuales vuelven a aparecer. Para corregir este comportamiento, volveremos a llamar a nuestro método cada vez que nuestra aplicación reciba el foco. Esto lo conseguimos sobrescribiendo el método onWindowsFocusChanged() de la clase AndroidLauncher:

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus) {
        // In KITKAT (4.4) and next releases, hide the virtual buttons
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            hideVirtualButtons();
        }
    }
}

Ahora sí, nuestra aplicación queda preparada para usar la pantalla completa.

Para obtener más información puede consultar la documentación oficial.

Espero que este articulo le haya sido de ayuda. Muchas gracias y un saludo!

 

2 comentarios en «Cómo ocultar los botones virtuales en Android / LibGDX»

  1. Hola, y si quisiera aprender a manejar esos botones ?, darle un evento especial a cada uno, al botón virtual de la fecha que regresa en especial?, espero resuelvas mi duda, saludos y gracias por este post.

    • Hola Jose,

      Por defecto ese botón no se captura al ser un evento especial del sistema. Para habilitar su captura hay que indicárselo explícitamente a libGDX mediante:

      Gdx.input.setCatchBackKey(true);

      Después, para comprobar si se ha pulsado podemos usar la constante Keys.BACK al capturar los eventos de botones:

      if(keycode == Keys.BACK){
          // hacer algo
      }

      Puedes encontrar más información en la documentación oficial de libGDX

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*