Únete a ⁠ #Android11: The Beta Launch Show el 3 de junio.

Navegación por gestos

A partir de Android 10 (nivel de API 29), el sistema Android es totalmente compatible con la navegación basada en gestos. Hay dos cosas que los desarrolladores deben hacer para asegurarse de que sus apps sean compatibles con esta función:

  • Extender el contenido de la app de un extremo a otro
  • Corregir gestos de apps conflictivos

Contenido de una app de un extremo a otro

Para aprovechar el espacio adicional en pantalla que ofrece la barra de navegación flotante, tendrás que hacer algunos cambios en tu app.

Cómo establecer barras del sistema transparentes

Puedes hacer eso si estableces los siguientes valores en tu tema:

<!-- values-29/themes.xml: -->

<style name="AppTheme" parent="...">
    <item name="android:navigationBarColor">@android:color/transparent</item>

    <!-- Optional, but recommended for full edge-to-edge rendering -->
    <item name="android:statusBarColor">@android:color/transparent</item>
</style>
Barra de navegación transparente con botones habilitados

De forma alternativa, puedes hacerlo usando Window.setNavigationBarColor() y Window.setStatusBarColor().

Cuando el dispositivo esté configurado para usar la navegación por gestos, y el fondo de la barra de navegación de tu app sea transparente, el sistema actualizará automáticamente el color del mando en función del color del contenido que se encuentre detrás de él. Sin embargo, cuando el usuario esté en el modo de navegación de 2 o 3 botones, esos botones no cambiarán de color. En su lugar, el sistema aplicará un fondo translúcido para que los botones permanezcan visibles. No obstante, el sistema solamente puede hacer eso si la app tiene como destino una API nivel 29 o superior.

Cómo establecer una marca de visibilidad de IU

Para poder diseñar una vista de un extremo a otro, tu app debe informar al sistema que puede encargarse de dicha vista. Para ello, usa View.setSystemUiVisibility() a fin de establecer las siguientes marcas:

Kotlin

view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
        or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)

Java

view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);

Juntas, esas marcas le indican al sistema que se debe presentar tu app en pantalla completa y como si las barras de navegación y de estado no estuvieran allí. Para eventos adicionales de pantalla completa, también puedes configurar SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, que te permite dibujar detrás de la barra de estado.

Si usas una clase de vista como CoordinatorLayout o DrawerLayout, que se encargan automáticamente de la barra de estado, es posible que las marcas SYSTEM_UI_FLAG_LAYOUT_STABLE y SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN ya estén configuradas. Además, si usas setSystemUiVisibility() para establecer otras marcas, como SYSTEM_UI_FLAG_IMMERSIVE, deberías asegurarte de que esas no reemplacen a las que se mencionaron anteriormente.

Incluso si tu app usa una vista de un extremo a otro, el sistema igual utiliza la API de WindowInsets para indicar dónde se encuentran las barras del sistema.

Cómo consumir inserciones manualmente

Si tu app utiliza una jerarquía de vistas personalizada, es posible que deba consumir manualmente las inserciones de ventanas del sistema. Para ello, se suele implementar una interfaz OnApplyWindowInsetsListener:

Kotlin

view.setOnApplyWindowInsetsListener() {v, insets ->
    insets.consumeSystemWindowInsets()

Java

view.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
    @Override
    public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
        // 1. Move views on top edge down by insets.getSystemWindowInsetTop()
        // 2. Move views on bottom edge up by insets.getSystemWindowInsetBottom()
        // 3. Also check getSystemWindowInsetLeft/Right(), such as for landscape
        // orientations
        return insets.consumeSystemWindowInsets();
    }
});

WindowInsets proporciona inserciones visuales para todas las barras del sistema mediante getSystemWindowInsets(). Asimismo, Android 10 agrega los siguientes métodos a WindowInsets:

Cómo resolver gestos de apps conflictivos

El modelo de navegación por gestos puede entrar en conflicto con gestos que antes utilizaban los desarrolladores de apps. En consecuencia, es posible que debas hacer ajustes en la interfaz de usuario de tu aplicación.

Conflictos con los gestos para retroceder

El nuevo gesto del sistema para retroceder es un deslizamiento hacia adentro desde el borde izquierdo o derecho de la pantalla. Esto puede interferir en los elementos de navegación de la app en esas áreas. Para mantener la funcionalidad de los elementos en los bordes izquierdo y derecho de la pantalla, deberás optar por no participar en el gesto para retroceder de forma selectiva indicando al sistema qué regiones necesitan recibir interacciones táctiles. Puedes hacerlo pasando List<Rect> a la API de View.setSystemGestureExclusionRects() que se introdujo en Android 10. Este método también está disponible en ViewCompat como androidx.core:core:1.1.0-dev01.

Por ejemplo:

Kotlin

var exclusionRects = listOf(rect1, rect2, rect3)

fun onLayout(
        changedCanvas: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
  // Update rect bounds and the exclusionRects list
  setSystemGestureExclusionRects(exclusionRects)
}

fun onDraw(canvas: Canvas) {
  // Update rect bounds and the exclusionRects list
  setSystemGestureExclusionRects(exclusionRects)
}

Java

List<Rect> exclusionRects;

public void onLayout(
        boolean changedCanvas, int left, int top, int right, int bottom) {
    // Update rect bounds and the exclusionRects list
    setSystemGestureExclusionRects(exclusionRects);
}

public void onDraw(Canvas canvas) {
    // Update rect bounds and the exclusionRects list
    setSystemGestureExclusionRects(exclusionRects);
}

Conflictos con gestos de Pantalla principal y Cambio rápido

Los nuevos gestos del sistema de Pantalla principal y Cambio rápido incluyen deslizamientos en la parte inferior de la pantalla, en el espacio que anteriormente ocupaba la barra de navegación. Las apps no pueden excluirse de estos gestos, como sí pueden hacerlo con el gesto para retroceder.

Para mitigar este problema, Android 10 introdujo la API de WindowInsets.getMandatorySystemGestureInsets(), que informa a las apps sobre los límites de reconocimiento táctil.

Juegos y otras apps que no tienen vistas

A menudo, los juegos y otras apps que no tienen una jerarquía de vistas requieren que el usuario se acerque a las áreas de gestos del sistema. En esos casos, los juegos pueden usar Window.setSystemGestureExclusionRects() para excluir las áreas que se superponen con las zonas reservadas para los gestos del sistema. Los juegos deben asegurarse de excluir estas áreas solo cuando sea necesario, como durante una partida.

Si un juego requiere que el usuario deslice el dedo cerca del área de gestos de la pantalla principal, la app puede solicitar que se coloque en modo inmersivo. Esto inhabilita los gestos del sistema mientras el usuario interactúa con el juego, pero le permite volver a habilitarlos deslizando el dedo por la parte inferior de la pantalla.

Recursos adicionales

Para obtener más información sobre la navegación por gestos, consulta los siguientes recursos adicionales.

Entradas de blog (inglés)

Videos (inglés)