Cómo garantizar la compatibilidad con la navegación por gestos

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

  • Extender el contenido de la app de borde a borde
  • Ocuparse de los gestos conflictivos de la app

Contenido de la app de borde a borde

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

Cómo establecer barras del sistema transparentes

Para configurar las barras, define 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

Como alternativa, puedes hacerlo de forma dinámica 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 controlador 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 con 2 o 3 botones, estos botones no cambiarán de color. En cambio, 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 mostrar tu vista de borde a borde, tu app debe indicar al sistema que puede admitir 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, estas 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 en pantalla completa adicionales, también puedes establecer 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 antes.

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 vista personalizada, es posible que deba consumir manualmente las inserciones de las 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(). Además, Android 10 agrega los siguientes métodos a WindowInsets:

Cómo ocuparse de los 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 con 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 un List<Rect> a la API de View.setSystemGestureExclusionRects() que se introdujo en Android 10. Este método también está disponible en ViewCompat a partir de 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 los gestos de pantalla principal y Quick Switch

Los nuevos gestos del sistema para ir a la pantalla de inicio y Quick Switch incluyen movimientos de deslizar en la parte inferior de la pantalla, en el espacio que antes ocupaba la barra de navegación. Las apps no pueden inhabilitar estos gestos, como sí pueden hacerlo con el gesto de atrás.

Para mitigar este problema, Android 10 presenta 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 áreas que se superponen con áreas reservadas para gestos del sistema. Es necesario asegurarse de que los juegos excluyan 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 principal, la app puede solicitar que se use el modo envolvente. De esta manera, se inhabilitan los gestos del sistema mientras el usuario interactúa con el juego, pero se permite que los usuarios deslicen el dedo desde la parte inferior de la pantalla para volver a habilitarlos.

Recursos adicionales

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

Entradas de blog

Videos