Mostrare i contenuti a tutto schermo nelle visualizzazioni

Prova Compose
Jetpack Compose è il toolkit per la UI consigliato per Android. Scopri come utilizzare la modalità edge-to-edge in Compose.

Una volta scelto come target l'SDK 35 o versioni successive su un dispositivo con Android 15 o versioni successive, la tua app viene visualizzata in modalità edge-to-edge. La finestra occupa l'intera larghezza e altezza del display disegnando dietro le barre di sistema. Le barre di sistema includono la barra di stato, la barra dei sottotitoli e la barra di navigazione.

Molte app hanno una barra dell'app in alto. La barra dell'app in alto deve estendersi fino al bordo superiore dello schermo ed essere visualizzata dietro la barra di stato. Se vuoi, la barra superiore dell'app può ridursi all'altezza della barra di stato quando i contenuti scorrono.

Molte app hanno anche una barra dell'app in basso o una barra di navigazione in basso. Queste barre devono anche estendersi fino al bordo inferiore dello schermo ed essere visualizzate dietro la barra di navigazione. In caso contrario, le app devono mostrare i contenuti scorrevoli dietro la barra di navigazione.

Figura 1. Barre di sistema in un layout edge-to-edge.

Quando implementi un layout edge-to-edge nella tua app, tieni presente quanto segue:

  1. Attiva la visualizzazione edge-to-edge
  2. Implementa layout adattivi per ottimizzare l'esperienza utente su diversi fattori di forma
  3. Gestisci eventuali sovrapposizioni visive
  4. Valuta la possibilità di mostrare scrim dietro le barre di sistema
un esempio di immagini dietro la barra di stato
Figura 2. Esempio di immagini dietro la barra di stato.

Attiva la visualizzazione edge-to-edge

Se la tua app ha come target l'SDK 35 o versioni successive, la modalità edge-to-edge viene attivata automaticamente per i dispositivi Android 15 o versioni successive.

Per attivare la modalità edge-to-edge nelle versioni precedenti di Android, chiama manualmente enableEdgeToEdge in onCreate di Activity.

Kotlin

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

Java

 @Override
      protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        WindowCompat.enableEdgeToEdge(getWindow());
        ...
      }

Per impostazione predefinita, enableEdgeToEdge() rende trasparenti le barre di sistema, tranne nella modalità di navigazione con tre pulsanti, in cui la barra di navigazione ha un velo traslucido. I colori delle icone di sistema e dello scrim vengono regolati in base al tema chiaro o scuro del sistema.

Per attivare la visualizzazione edge-to-edge nella tua app senza utilizzare la funzione enableEdgeToEdge(), consulta Configura manualmente la visualizzazione edge-to-edge.

Gestisci le sovrapposizioni utilizzando gli inset

Alcune visualizzazioni dell'app potrebbero essere disegnate dietro le barre di sistema, come mostrato nella figura 3.

Puoi risolvere le sovrapposizioni reagendo agli inset, che specificano quali parti dello schermo si intersecano con la UI di sistema, come la barra di navigazione o la barra di stato. L'intersezione può significare la visualizzazione sopra i contenuti, ma può anche informare l'app sui gesti di sistema.

I tipi di inset che si applicano alla visualizzazione edge-to-edge della tua app sono:

  • Inset delle barre di sistema:ideali per le visualizzazioni toccabili e che non devono essere oscurate visivamente dalle barre di sistema.

  • Inset del ritaglio display:per le aree in cui potrebbe essere presente un ritaglio dello schermo a causa della forma del dispositivo.

  • Inset dei gesti di sistema:per le aree di navigazione tramite gesti utilizzate dal sistema che hanno la priorità sulla tua app.

Inset delle barre di sistema

Gli inset della barra di sistema sono il tipo di inset di uso comune. Rappresentano l'area in cui la UI di sistema viene visualizzata sull'asse Z sopra l'app. Sono ideali per spostare o aggiungere spaziatura interna alle visualizzazioni dell'app che sono toccabili e che non devono essere oscurate visivamente dalle barre di sistema.

Ad esempio, il Floating Action Button (FAB) nella Figura 3 è parzialmente oscurato dalla barra di navigazione:

un esempio di implementazione edge-to-edge, ma la barra di navigazione copre il FAB
Figura 3. Barra di navigazione che si sovrappone a un FAB in un layout edge-to-edge.

Per evitare questo tipo di sovrapposizione visiva in modalità di navigazione tramite gesti o tramite pulsanti, puoi aumentare i margini della visualizzazione utilizzando getInsets(int) con WindowInsetsCompat.Type.systemBars().

Il seguente esempio di codice mostra come implementare gli inserti della barra di 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 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 the window insets to keep passing
  // down to descendant views.
    return WindowInsetsCompat.CONSUMED;
});

Se applichi questa soluzione all'esempio mostrato nella figura 3, non si verifica alcuna sovrapposizione visiva in modalità pulsante, come mostrato nella figura 4:

una barra di navigazione traslucida che non copre il FAB
Figura 4. Risoluzione della sovrapposizione visiva in modalità pulsante.

Lo stesso vale per la modalità di navigazione tramite gesti, come mostrato nella figura 5:

edge-to-edge con navigazione tramite gesti
Figura 5. Risoluzione della sovrapposizione visiva in modalità di navigazione tramite gesti.

Inset del ritaglio display

Alcuni dispositivi hanno ritagli display. In genere, il ritaglio si trova nella parte superiore dello schermo ed è incluso nella barra di stato. Quando lo schermo del dispositivo è in modalità Orizzontale, il ritaglio potrebbe trovarsi sul bordo verticale. A seconda dei contenuti mostrati dall'app sullo schermo, devi implementare il padding per evitare i ritagli display, poiché per impostazione predefinita le app vengono visualizzate nel ritaglio display.

Ad esempio, molte schermate delle app mostrano un elenco di elementi. Non oscurare gli elementi dell'elenco con il ritaglio display o le barre di 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;
});

Determina il valore di WindowInsetsCompat prendendo l'or logico delle barre di sistema e dei tipi di ritaglio display.

Imposta clipToPadding su RecyclerView in modo che il padding scorra con gli elementi dell'elenco. In questo modo, gli elementi possono andare dietro le barre di sistema quando l'utente scorre, come mostrato nell'esempio seguente.

<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" />

Inset dei gesti di sistema

Gli inserti dei gesti di sistema rappresentano le aree della finestra in cui i gesti di sistema hanno la priorità sulla tua app. Queste aree sono mostrate in arancione nella Figura 6:

Un esempio di aree dei gesti di sistema
Figura 6. Inset dei gesti di sistema.

Come per gli inset della barra di sistema, puoi evitare la sovrapposizione degli inset dei gesti di sistema utilizzando getInsets(int) con WindowInsetsCompat.Type.systemGestures().

Utilizza questi inserti per spostare o aggiungere spaziatura interna alle visualizzazioni scorrevoli lontano dai bordi. I casi d'uso comuni includono riquadri inferiori, scorrimento nei giochi e caroselli implementati utilizzando ViewPager2.

Su Android 10 o versioni successive, gli inset dei gesti di sistema contengono un inset inferiore per il gesto Home e un inset sinistro e destro per i gesti Indietro:

un esempio di misurazioni degli inserti dei gesti di sistema
Figura 7. Misurazioni degli inset dei gesti di sistema.

Il seguente esempio di codice mostra come implementare gli inserti dei gesti di 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;
});

Componenti di Material Design

Molti componenti di Material Design per Android basati su visualizzazioni (com.google.android.material) gestiscono automaticamente gli inset, tra cui BottomAppBar, BottomNavigationView, NavigationRailView e NavigationView.

Tuttavia, AppBarLayout non gestisce automaticamente gli inset. Aggiungi android:fitsSystemWindows="true" per gestire gli inset superiori.

Scopri come gestire gli inset con i componenti Material in Compose.

Invio di inset compatibile con le versioni precedenti

Per interrompere l'invio degli inset alle visualizzazioni secondarie ed evitare un padding eccessivo, puoi utilizzare gli inset con la costante WindowInsetsCompat.CONSUMED. Tuttavia, sui dispositivi con Android 10 (livello API 29 e versioni precedenti), gli inset non vengono inviati agli elementi di pari livello dopo la chiamata a WindowInsetsCompat.CONSUMED, il che può causare una sovrapposizione visiva involontaria.

Esempio di invio di un inset con errori
Figura 8. Esempio di invio di inset non funzionante. Gli inset non vengono inviati alle visualizzazioni di pari livello dopo che ViewGroup 1 li ha utilizzati su Android 10 (livello API 29) e versioni precedenti, causando la sovrapposizione di TextView 2 con la barra di navigazione di sistema. Tuttavia, gli inset vengono inviati alle visualizzazioni di pari livello su Android 11 (livello API 30) e versioni successive, come previsto.

Per verificare che gli inset vengano inviati agli elementi di pari livello per tutte le versioni di Android supportate, utilizza ViewGroupCompat#installCompatInsetsDispatch prima di utilizzare gli inset, disponibile su AndroidX Core e Core-ktx 1.16.0-alpha01 e versioni successive.

Kotlin

// Use the i.d. assigned to your layout's root view, e.g. R.id.main
val rootView = findViewById(R.id.main)
// Call before consuming insets
ViewGroupCompat.installCompatInsetsDispatch(rootView)

Java

// Use the i.d. assigned to your layout's root view, e.g. R.id.main
LinearLayout rootView = findViewById(R.id.main);
// Call before consuming insets
ViewGroupCompat.installCompatInsetsDispatch(rootView);
Esempio di invio di inset fissi
Figura 9. Risolto il problema relativo all'invio degli inset dopo la chiamata a ViewGroupCompat#installCompatInsetsDispatch.

Modalità immersiva

Alcuni contenuti vengono visualizzati meglio a schermo intero, offrendo all'utente un'esperienza più coinvolgente. Puoi nascondere le barre di sistema per la modalità immersiva utilizzando le librerie WindowInsetsController e 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());

Per saperne di più sull'implementazione di questa funzionalità, consulta Nascondi le barre di sistema per la modalità immersiva.

Icone della barra di sistema

La chiamata a enableEdgeToEdge garantisce che i colori delle icone della barra di sistema vengano aggiornati quando il tema del dispositivo cambia.

Quando utilizzi la modalità edge-to-edge, potresti dover aggiornare manualmente i colori delle icone della barra di sistema in modo che siano in contrasto con lo sfondo dell'app. Ad esempio, per creare icone della barra di stato chiare:

Kotlin

WindowCompat.getInsetsController(window, window.decorView)
    .isAppearanceLightStatusBars = false

Java

WindowCompat.getInsetsController(window, window.getDecorView())
    .setAppearanceLightStatusBars(false);

Protezione della barra di sistema

Una volta che la tua app ha come target l'SDK 35 o versioni successive, viene applicata la modalità edge-to-edge. La barra di stato del sistema e le barre di navigazione tramite gesti sono trasparenti, ma la barra di navigazione con tre pulsanti è semitrasparente. Chiama enableEdgeToEdge per renderlo compatibile con le versioni precedenti.

Tuttavia, le impostazioni predefinite del sistema potrebbero non funzionare per tutti i casi d'uso. Consulta le linee guida per la progettazione delle barre di sistema Android e il design edge-to-edge per determinare se utilizzare barre di sistema trasparenti o semitrasparenti.

Crea barre di sistema trasparenti

Crea una barra di stato trasparente scegliendo come target Android 15 (SDK 35) o versioni successive o chiamando enableEdgeToEdge() con argomenti predefiniti per le versioni precedenti.

Crea una barra di navigazione tramite gesti trasparente scegliendo come target Android 15 o versioni successive o chiamando enableEdgeToEdge() con argomenti predefiniti per le versioni precedenti. Per la barra di navigazione a tre pulsanti, imposta Window.setNavigationBarContrastEnforced su false, altrimenti verrà applicato un velo traslucido.

Crea barre di sistema traslucide

Per creare una barra di stato traslucida:

  1. Aggiorna la dipendenza androidx-core alla versione 1.16.0-beta01 o successiva
  2. Aggrega il layout XML in androidx.core.view.insets.ProtectionLayout e assegna un ID.
  3. Accedi in modo programmatico a ProtectionLayout per impostare le protezioni, specificando il lato e un GradientProtection per la barra di stato.

<androidx.core.view.insets.ProtectionLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/list_protection"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ScrollView
        android:id="@+id/item_list"
        android:clipToPadding="false"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <!--items-->

    </ScrollView>

</androidx.core.view.insets.ProtectionLayout>

findViewById<ProtectionLayout>(R.id.list_protection)
    .setProtections(
        listOf(
            GradientProtection(
                WindowInsetsCompat.Side.TOP,
                // Ideally, this is the pane's background color
                paneBackgroundColor
            )
        )
    )

Assicurati che il valore ColorInt passato a GradientProtection corrisponda allo sfondo dei contenuti. Ad esempio, un layout elenco-dettagli visualizzato su un pieghevole potrebbe avere GradientProtections diversi di colori diversi per il riquadro dell'elenco e il riquadro dei dettagli.

Figura 1. Protezione con gradiente di colori diversi.

Non creare una barra di navigazione tramite gesti traslucida. Per creare una barra di navigazione a tre pulsanti traslucida, esegui una delle seguenti operazioni:

  • Se il tuo layout è già inserito in un ProtectionView, puoi passare un ColorProtection o un GradientProtection aggiuntivo al metodo setProtections. Prima di farlo, assicurati che window.isNavigationBarContrastEnforced = false.
  • In caso contrario, imposta window.isNavigationBarContrastEnforced = true.

Altri suggerimenti

Ulteriori suggerimenti per la gestione degli inset.

Visualizza i contenuti a scorrimento edge-to-edge

Verifica che l'ultimo elemento dell'elenco non sia oscurato dalle barre di sistema nel tuo RecyclerView o NestedScrollView gestendo gli inset e impostando clipToPadding su false.

Il seguente video mostra un RecyclerView con la visualizzazione edge-to-edge disattivata (a sinistra) e attivata (a destra):

Per un esempio di codice, consulta gli snippet di codice nella sezione Crea elenchi dinamici con RecyclerView.

Crea finestre di dialogo a schermo intero edge-to-edge

Per rendere i dialoghi a schermo intero edge-to-edge, chiama enableEdgeToEdge sul dialogo.

Kotlin

class MyAlertDialogFragment : DialogFragment() {
    override fun onStart(){
        super.onStart()
        dialog?.window?.let { WindowCompat.enableEdgeToEdge(it) }
    }
    ...
}

Java

public class MyAlertDialogFragment extends DialogFragment {
    @Override
    public void onStart() {
        super.onStart();
        Dialog dialog = getDialog();
        if (dialog != null) {
            Window window = dialog.getWindow();
            if (window != null) {
                WindowCompat.enableEdgeToEdge(window);
            }
        }
    }
    ...
}

Risorse aggiuntive

Per saperne di più sulla visualizzazione edge-to-edge, consulta i seguenti riferimenti.

Blog

Design

Altra documentazione

Video