Cómo mostrar el contenido de borde a borde en la app

Prueba la forma de Compose
Jetpack Compose es el kit de herramientas de IU recomendado para Android. Descubre cómo trabajar con el diseño de borde a borde en Compose.

Una vez que segmentes tu app para el SDK 35 o versiones posteriores en un dispositivo con Android 15 o versiones posteriores, esta se mostrará de borde a borde. La ventana abarca todo el ancho y la altura de la pantalla dibujando detrás de las barras del sistema. Las barras del sistema incluyen la barra de estado, la barra de leyendas y la barra de navegación.

Muchas apps tienen una barra superior. La barra superior de la app debe extenderse hasta el borde superior de la pantalla y mostrarse detrás de la barra de estado. De manera opcional, la barra superior de la app puede reducirse a la altura de la barra de estado cuando se desplaza el contenido.

Muchas apps también tienen una barra de la app o una barra de navegación inferior. Estas barras también deben extenderse hasta el borde inferior de la pantalla y mostrarse detrás de la barra de navegación. De lo contrario, las apps deben mostrar contenido desplazable detrás de la barra de navegación.

Figura 1. Barras del sistema en un diseño de borde a borde

Cuando implementes un diseño de borde a borde en tu app, ten en cuenta lo siguiente:

  1. Habilita una pantalla de borde a borde
  2. Controla las superposiciones visuales.
  3. Considera mostrar cortinillas detrás de las barras del sistema.
ejemplo de imágenes detrás de la barra de estado
Figura 2: Ejemplo de imágenes detrás de la barra de estado.

Habilita la pantalla de borde a borde

Si tu app se orienta al SDK 35 o versiones posteriores, el modo de pantalla completa se habilita automáticamente para dispositivos con Android 15 o versiones posteriores.

Para habilitar el modo de pantalla completa en versiones anteriores de Android, haz lo siguiente:

  1. Agrega una dependencia a la biblioteca androidx.activity en el archivo build.gradle de tu app o módulo:

    Kotlin

    dependencies {
        val activity_version = activity_version
        // Java language implementation
        implementation("androidx.activity:activity:$activity_version")
        // Kotlin
        implementation("androidx.activity:activity-ktx:$activity_version")
    }

    Groovy

    dependencies {
        def activity_version = activity_version
        // Java language implementation
        implementation 'androidx.activity:activity:$activity_version'
        // Kotlin
        implementation 'androidx.activity:activity-ktx:$activity_version'
    }
  2. Importa la función de extensión enableEdgeToEdge a tu app:

Para habilitar el modo de borde a borde de forma manual, llama a enableEdgeToEdge en onCreate de tu Activity. Se debe llamar antes de setContentView.

Kotlin

     override fun onCreate(savedInstanceState: Bundle?) {
       enableEdgeToEdge()
       super.onCreate(savedInstanceState)
       ...
     }
   

Java

     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
       EdgeToEdge.enable(this);
       super.onCreate(savedInstanceState);
       ...
     }
   

De forma predeterminada, enableEdgeToEdge() hace que las barras del sistema sean transparentes, excepto en el modo de navegación de 3 botones, en el que la barra de estado obtiene una pantalla translúcida. Los colores de los íconos del sistema y la pantalla parpadeante se ajustan según el tema claro o oscuro del sistema.

La función enableEdgeToEdge() declara automáticamente que la app debe diseñarse de borde a borde y ajusta los colores de las barras del sistema.

Para habilitar la pantalla de borde a borde en tu app sin usar la función enableEdgeToEdge(), consulta Cómo configurar manualmente la pantalla de borde a borde.

Controla las superposiciones con inserciones

Es posible que algunas de las vistas de tu app se dibujen detrás de las barras del sistema, como se muestra en la Figura 3.

Puedes abordar las superposiciones reaccionando a los inserciones, que especifican qué partes de la pantalla se cruzan con la IU del sistema, como la barra de navegación o la barra de estado. La intersección puede significar que se muestra sobre el contenido, pero también puede informar a tu app sobre los gestos del sistema.

Los tipos de inserciones que se aplican para mostrar tu app de borde a borde son los siguientes:

  • Inserciones de barras del sistema: Son ideales para las vistas que se pueden presionar y que no deben estar ocultas visualmente por las barras del sistema.

  • Insertos de corte de pantalla: Para áreas en las que puede haber un corte de pantalla debido a la forma del dispositivo.

  • Inserciones de gestos del sistema: Para las áreas de navegación por gestos que usa el sistema y que tienen prioridad sobre tu app.

Inserciones de las barras del sistema

Los elementos insertados en la barra del sistema son el tipo de inserción más utilizado. Representan el área en la que se muestra la IU del sistema en el eje Z sobre tu app. Se usan mejor para mover o rellenar vistas en tu app que se pueden presionar y que no deben estar ocultas visualmente por las barras del sistema.

Por ejemplo, la barra de navegación oculta parcialmente el botón de acción flotante (BAF) de la Figura 3:

Un ejemplo de implementación de pantalla completa, pero la barra de navegación cubre el BAF
Figura 3: Barra de navegación que se superpone con un FAB en un diseño de borde a borde

Para evitar este tipo de superposición visual en el modo de gestos o en el modo de botones, puedes aumentar los márgenes de la vista con getInsets(int) con WindowInsetsCompat.Type.systemBars().

En el siguiente ejemplo de código, se muestra cómo implementar los rellenos de la barra del sistema:

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(fab) { v, windowInsets ->
  val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
  // Apply the insets as a margin to the view. This solution sets
  // only the bottom, left, and right dimensions, but you can apply whichever
  // insets are appropriate to your layout. You can also update the view padding
  // if that's more appropriate.
  v.updateLayoutParams<MarginLayoutParams> {
      leftMargin = insets.left
      bottomMargin = insets.bottom
      rightMargin = insets.right
  }

  // Return CONSUMED if you don't want want the window insets to keep passing
  // down to descendant views.
  WindowInsetsCompat.CONSUMED
}

Java

ViewCompat.setOnApplyWindowInsetsListener(fab, (v, windowInsets) -> {
  Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
  // Apply the insets as a margin to the view. This solution sets only the
  // bottom, left, and right dimensions, but you can apply whichever insets are
  // appropriate to your layout. You can also update the view padding if that's
  // more appropriate.
  MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
  mlp.leftMargin = insets.left;
  mlp.bottomMargin = insets.bottom;
  mlp.rightMargin = insets.right;
  v.setLayoutParams(mlp);

  // Return CONSUMED if you don't want want the window insets to keep passing
  // down to descendant views.
    return WindowInsetsCompat.CONSUMED;
});

Si aplicas esta solución al ejemplo que se muestra en la figura 3, no se superpondrá visualmente en el modo de botón, como se muestra en la figura 4:

una barra de navegación translúcida que no cubre el BAF
Figura 4: Se resolvió la superposición visual en el modo de botones.

Lo mismo se aplica al modo de navegación por gestos, como se muestra en la figura 5:

de borde a borde con navegación por gestos
Figura 5: Se resolvió la superposición visual en el modo de navegación por gestos.

Cómo mostrar inserciones de recortes de pantalla

Algunos dispositivos tienen recortes en la pantalla. Por lo general, el recorte se encuentra en la parte superior de la pantalla y se incluye en la barra de estado. Cuando la pantalla del dispositivo está en modo horizontal, el corte puede estar en el borde vertical. Según el contenido que muestre tu app en la pantalla, debes implementar padding para evitar los recortes de pantalla, ya que, de forma predeterminada, las apps dibujarán en el recorte de pantalla.

Por ejemplo, muchas pantallas de apps muestran una lista de elementos. No ocultes los elementos de la lista con el recorte de la pantalla ni las barras del sistema.

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(binding.recyclerView) { v, insets ->
  val bars = insets.getInsets(
    WindowInsetsCompat.Type.systemBars()
      or WindowInsetsCompat.Type.displayCutout()
  )
  v.updatePadding(
    left = bars.left,
    top = bars.top,
    right = bars.right,
    bottom = bars.bottom,
  )
  WindowInsetsCompat.CONSUMED
}

Java

ViewCompat.setOnApplyWindowInsetsListener(mBinding.recyclerView, (v, insets) -> {
  Insets bars = insets.getInsets(
    WindowInsetsCompat.Type.systemBars()
    | WindowInsetsCompat.Type.displayCutout()
  );
  v.setPadding(bars.left, bars.top, bars.right, bars.bottom);
  return WindowInsetsCompat.CONSUMED;
});

Para determinar el valor de WindowInsetsCompat, toma el o lógico de las barras del sistema y los tipos de recortes de la pantalla.

Establece clipToPadding en RecyclerView para que el padding se desplace con los elementos de la lista. Esto permite que los elementos se oculten detrás de las barras del sistema cuando el usuario se desplaza, como se muestra en el siguiente ejemplo.

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

Inserciones de gestos del sistema

Las inserciones de gestos del sistema representan las áreas de la ventana en las que los gestos del sistema tienen prioridad sobre tu app. Estas áreas se muestran en naranja en la Figura 6:

Ejemplo de inserciones de gestos del sistema
Figura 6: Inserciones de gestos del sistema.

Al igual que con los rellenos de la barra del sistema, puedes evitar superponer los rellenos de gestos del sistema con getInsets(int) con WindowInsetsCompat.Type.systemGestures().

Usa estas inserciones para mover o acolchar vistas deslizables lejos de los bordes. Los casos de uso comunes incluyen hojas inferiores, deslizamientos en juegos y carruseles implementados con ViewPager2.

En Android 10 o versiones posteriores, los inserciones de gestos del sistema contienen una inserción inferior para el gesto de inicio y una inserción izquierda y derecha para los gestos atrás:

Ejemplo de mediciones de desplazamiento del gesto del sistema
Figura 7: Mediciones de inserción de gestos del sistema

En el siguiente ejemplo de código, se muestra cómo implementar inserciones de gestos del sistema:

Kotlin

ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets ->
    val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures())
    // Apply the insets as padding to the view. Here, set all the dimensions
    // as appropriate to your layout. You can also update the view's margin if
    // more appropriate.
    view.updatePadding(insets.left, insets.top, insets.right, insets.bottom)

    // Return CONSUMED if you don't want the window insets to keep passing down
    // to descendant views.
    WindowInsetsCompat.CONSUMED
}

Java

ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
    Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures());
    // Apply the insets as padding to the view. Here, set all the dimensions
    // as appropriate to your layout. You can also update the view's margin if
    // more appropriate.
    view.setPadding(insets.left, insets.top, insets.right, insets.bottom);

    // Return CONSUMED if you don't want the window insets to keep passing down
    // to descendant views.
    return WindowInsetsCompat.CONSUMED;
});

Componentes de Material

Muchos componentes de Material de Android (com.google.android.material){:.external} basados en objetos View controlan automáticamente las inserciones, incluidas BottomAppBar, BottomNavigationView, NavigationRailView y NavigationView.

Sin embargo, AppBarLayout no controla automáticamente los rellenos. Agrega android:fitsSystemWindows="true" para controlar las inserciones superiores.

Obtén información para controlar los rellenos con componentes de Material en Compose.

Modo envolvente

Algunos contenidos se experimentan mejor en pantalla completa, lo que le brinda al usuario una experiencia más envolvente. Puedes ocultar las barras del sistema para el modo envolvente con las bibliotecas WindowInsetsController y WindowInsetsControllerCompat:

Kotlin

val windowInsetsController =
      WindowCompat.getInsetsController(window, window.decorView)

// Hide the system bars.
windowInsetsController.hide(Type.systemBars())

// Show the system bars.
windowInsetsController.show(Type.systemBars())

Java

Window window = getWindow();
WindowInsetsControllerCompat windowInsetsController =
      WindowCompat.getInsetsController(window, window.getDecorView());
if (windowInsetsController == null) {
    return;
  }
// Hide the system bars.
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());

// Show the system bars.
windowInsetsController.show(WindowInsetsCompat.Type.systemBars());

Consulta Oculta las barras del sistema para el modo envolvente para obtener más información sobre cómo implementar esta función.

Protección de la barra del sistema

Una vez que tu app se oriente al SDK 35 o versiones posteriores, se aplicará el diseño de pantalla completa. La barra de estado del sistema y las barras de navegación por gestos son transparentes, pero la barra de navegación con tres botones es traslúcida.

Para quitar la protección en segundo plano predeterminada de la navegación con tres botones traslúcida, establece Window.setNavigationBarContrastEnforced en false.

Recursos adicionales

Consulta las siguientes referencias para obtener más información sobre WindowInsets, la navegación con gestos y cómo funcionan los elementos intercalados: