Inhalte in Ansichten randlos anzeigen

Compose ausprobieren
Jetpack Compose ist das empfohlene UI-Toolkit für Android. Informationen zur Verwendung von Edge-to-Edge in Compose

Sobald Sie auf einem Gerät mit Android 15 oder höher auf SDK 35 oder höher ausgerichtet sind, wird Ihre App randlos angezeigt. Das Fenster erstreckt sich über die gesamte Breite und Höhe des Displays, indem es hinter den Systemleisten gerendert wird. Zu den Systemleisten gehören die Statusleiste, die Untertitelzeile und die Navigationsleiste.

Viele Apps haben eine obere App-Leiste. Die obere App-Leiste sollte sich bis zum oberen Rand des Displays erstrecken und hinter der Statusleiste angezeigt werden. Optional kann die obere App-Leiste beim Scrollen des Inhalts auf die Höhe der Statusleiste verkleinert werden.

Viele Apps haben auch eine untere App-Leiste oder eine untere Navigationsleiste. Diese Balken sollten sich auch bis zum unteren Bildschirmrand erstrecken und hinter der Navigationsleiste angezeigt werden. Andernfalls sollten Apps scrollende Inhalte hinter der Navigationsleiste anzeigen.

Abbildung 1. Systemleisten in einem randlosen Layout.

Beachten Sie bei der Implementierung eines Edge-to-Edge-Layouts in Ihrer App Folgendes:

  1. Randlose Anzeige aktivieren
  2. Visuelle Überschneidungen beheben
  3. Erwägen Sie, Scrims hinter den Systemleisten zu platzieren.
Beispiel für Bilder hinter der Statusleiste
Abbildung 2. Beispiel für Bilder hinter der Statusleiste.

Randlose Anzeige aktivieren

Wenn Ihre App auf SDK 35 oder höher ausgerichtet ist, wird die randlose Anzeige automatisch für Geräte mit Android 15 oder höher aktiviert.

Wenn Sie die Darstellung von Rand zu Rand in früheren Android-Versionen aktivieren möchten, rufen Sie enableEdgeToEdge in onCreate Ihres Activity manuell auf.

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());
        ...
      }

Standardmäßig macht enableEdgeToEdge() die Systemleisten transparent. Beim Navigationsmodus mit drei Schaltflächen erhält die Statusleiste jedoch einen durchscheinenden Schleier. Die Farben der Systemsymbole und des Scrim werden je nach hellem oder dunklem Systemdesign angepasst.

Informationen zum Aktivieren der randlosen Anzeige in Ihrer App ohne Verwendung der Funktion enableEdgeToEdge() finden Sie hier.

Überlappungen mit Insets beheben

Einige Ansichten Ihrer App werden möglicherweise hinter den Systemleisten gerendert, wie in Abbildung 3 dargestellt.

Sie können Überschneidungen beheben, indem Sie auf Insets reagieren. Diese geben an, welche Teile des Bildschirms sich mit der System-UI wie der Navigationsleiste oder der Statusleiste überschneiden. Das kann bedeuten, dass die Anzeige über dem Inhalt erfolgt, aber auch, dass Ihre App über Systemgesten informiert wird.

Folgende Arten von Insets gelten für die randlose Anzeige Ihrer App:

  • Systemleisten-Einzüge:Am besten für Ansichten, die getippt werden können und nicht durch die Systemleisten verdeckt werden dürfen.

  • Display-Aussparungseinsätze:für Bereiche, in denen aufgrund der Form des Geräts eine Display-Aussparung vorhanden sein kann.

  • System-Gesten-Insets:für Bereiche, die vom System für die Bedienung über Gesten verwendet werden und die Priorität vor Ihrer App haben.

Systemleisten-Insets

Systemleisten-Insets sind die am häufigsten verwendeten Insets. Sie stellen den Bereich dar, in dem die System-UI in der Z-Achse über Ihrer App angezeigt wird. Sie eignen sich am besten, um Ansichten in Ihrer App zu verschieben oder zu polstern, die angeklickt werden können und nicht visuell durch die Systemleisten verdeckt werden dürfen.

In Abbildung 3 wird beispielsweise der Floating-Action-Button (FAB) teilweise von der Navigationsleiste verdeckt:

Beispiel für die Edge-to-Edge-Implementierung, bei der die Navigationsleiste das schwebende Aktionsschaltfläche verdeckt
Abbildung 3: Die Navigationsleiste überlappt einen schwebenden Aktionsbutton in einem Edge-to-Edge-Layout.

Um diese Art von visueller Überschneidung im Gesten- oder Schaltflächenmodus zu vermeiden, können Sie die Ränder der Ansicht mit getInsets(int) und WindowInsetsCompat.Type.systemBars() vergrößern.

Das folgende Codebeispiel zeigt, wie Systemleisten-Insets implementiert werden:

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;
});

Wenn Sie diese Lösung auf das Beispiel in Abbildung 3 anwenden, kommt es im Schaltflächenmodus zu keiner visuellen Überschneidung, wie in Abbildung 4 dargestellt:

Eine durchscheinende Navigationsleiste, die das UAS nicht verdeckt
Abbildung 4: Visuelle Überschneidungen im Schaltflächenmodus wurden behoben.

Das Gleiche gilt für den Gestennavigationsmodus, wie in Abbildung 5 dargestellt:

randlos mit Bedienung über Gesten
Abbildung 5: Visuelle Überschneidungen bei der Bedienung über Gesten wurden behoben.

Display-Aussparung

Einige Geräte haben Displayausschnitte. Normalerweise befindet sich der Ausschnitt oben auf dem Display und ist in der Statusleiste enthalten. Wenn sich das Display des Geräts im Querformat befindet, kann sich das Ausschnitt an der vertikalen Kante befinden. Je nach den Inhalten, die in Ihrer App auf dem Bildschirm angezeigt werden, sollten Sie das Padding implementieren, um Displayausschnitte zu vermeiden. Standardmäßig werden Apps im Displayausschnitt gerendert.

Viele App-Bildschirme zeigen beispielsweise eine Liste von Elementen an. Listenelemente dürfen nicht durch das Display-Cutout oder die Systemleisten verdeckt werden.

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;
});

Bestimmen Sie den Wert von WindowInsetsCompat, indem Sie die Systemleisten- und Displayausschnitttypen oder-verknüpfen.

Legen Sie clipToPadding auf RecyclerView fest, damit der Innenabstand mit den Listenelementen gescrollt wird. So können die Elemente beim Scrollen des Nutzers hinter den Systemleisten verschwinden, wie im folgenden Beispiel gezeigt.

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

System-Gesten-Insets

Systemgesten-Insets stellen die Bereiche des Fensters dar, in denen Systemgesten Vorrang vor Ihrer App haben. Diese Bereiche sind in Abbildung 6 orange dargestellt:

Beispiel für Systemgesten-Insets
Abbildung 6: Systemgesten-Insets

Wie bei den Systemleisten-Insets können Sie auch bei den Systemgesten-Insets Überschneidungen vermeiden, indem Sie getInsets(int) mit WindowInsetsCompat.Type.systemGestures() verwenden.

Mit diesen Insets können Sie wischbare Ansichten von den Rändern weg verschieben oder auffüllen. Häufige Anwendungsfälle sind Bottom Sheets, Wischen in Spielen und Karussells, die mit ViewPager2 implementiert werden.

Unter Android 10 und höher enthalten Systemgesten-Insets einen unteren Inset für die Home-Geste sowie einen linken und einen rechten Inset für die Zurück-Gesten:

Beispiel für die Inset-Messungen von Systemgesten
Abbildung 7. Messungen für den Einzug von Systemgesten.

Das folgende Codebeispiel zeigt, wie Sie Systemgesten-Insets implementieren:

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;
});

Materialkomponenten

Viele ansichtsbasierte Android Material Components (com.google.android.material) verarbeiten Insets automatisch, einschließlich BottomAppBar, BottomNavigationView, NavigationRailView und NavigationView.

AppBarLayout verarbeitet Insets jedoch nicht automatisch. Fügen Sie android:fitsSystemWindows="true" hinzu, um obere Insets zu verarbeiten.

Informationen zum Umgang mit Insets finden Sie unter Material Components in Compose.

Abwärtskompatible Inset-Auslieferung

Wenn Sie verhindern möchten, dass Insets an untergeordnete Ansichten gesendet werden, und eine zu große Auffüllung vermeiden möchten, können Sie Insets mit der Konstante WindowInsetsCompat.CONSUMED verwenden. Auf Geräten mit Android 10 (API-Level 29 und niedriger) werden Insets jedoch nicht an untergeordnete Elemente gesendet, nachdem WindowInsetsCompat.CONSUMED aufgerufen wurde. Dies kann zu unbeabsichtigten visuellen Überschneidungen führen.

Beispiel für fehlerhaftes Inset-Dispatching
Abbildung 8: Beispiel für fehlerhaftes Inset-Dispatching. Insets werden nicht an nebeneinanderliegende Ansichten weitergeleitet, nachdem ViewGroup 1 Insets unter Android 10 (API-Level 29) und früher verarbeitet hat. Dadurch überlappt TextView 2 mit der Systemnavigationsleiste. Unter Android 11 (API‑Level 30) und höher werden Insets jedoch wie erwartet an untergeordnete Ansichten gesendet.

Wenn Sie sichergehen möchten, dass Insets für alle unterstützten Android-Versionen an Geschwister weitergeleitet werden, verwenden Sie ViewGroupCompat#installCompatInsetsDispatch, bevor Sie Insets nutzen. Diese Funktion ist in AndroidX Core und Core-ktx 1.16.0-alpha01 und höher verfügbar.

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);
Beispiel für das Senden von Insets mit fester Größe
Abbildung 9: Das Problem mit dem Inset-Dispatching nach dem Aufrufen von „ViewGroupCompat#installCompatInsetsDispatch“ wurde behoben.

Immersiver Modus

Bestimmte Inhalte lassen sich am besten im Vollbildmodus wiedergeben, da dies die Nutzererfahrung verbessert. Sie können die Systemleisten für den immersiven Modus mit den Bibliotheken WindowInsetsController und WindowInsetsControllerCompat ausblenden:

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());

Weitere Informationen zur Implementierung dieser Funktion finden Sie unter Systemleisten für den Immersive-Modus ausblenden.

Symbole in der Systemleiste

Durch den Aufruf von enableEdgeToEdge werden die Farben der Symbole in der Systemleiste aktualisiert, wenn sich das Gerätedesign ändert.

Wenn Sie die App über den gesamten Bildschirmrand hinweg anzeigen, müssen Sie möglicherweise die Farben der Symbole in der Systemleiste manuell aktualisieren, damit sie sich vom Hintergrund Ihrer App abheben. So erstellen Sie beispielsweise helle Statusleistensymbole:

Kotlin

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

Java

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

Schutz der Systemleiste

Sobald Ihre App auf SDK 35 oder höher ausgerichtet ist, wird Edge-to-Edge erzwungen. Die Systemstatusleiste und die Navigationsleisten für die Gestensteuerung sind transparent, die Navigationsleiste für die 3‑Schaltflächen-Steuerung ist jedoch durchscheinend. Rufen Sie enableEdgeToEdge auf, um die Abwärtskompatibilität zu gewährleisten.

Die Standardeinstellungen des Systems sind jedoch möglicherweise nicht für alle Anwendungsfälle geeignet. In der Anleitung zum Design von Android-Systemleisten und im Edge-to-Edge-Design finden Sie Informationen dazu, ob Sie transparente oder durchscheinende Systemleisten verwenden sollten.

Transparente Systemleisten erstellen

Sie können eine transparente Statusleiste erstellen, indem Sie auf Android 15 (SDK 35) oder höher ausgerichtet sind oder enableEdgeToEdge() mit Standardargumenten für frühere Versionen aufrufen.

Sie können eine transparente Navigationsleiste für die Touchbedienung erstellen, indem Sie Android 15 oder höher als Zielversion festlegen oder enableEdgeToEdge() mit Standardargumenten für frühere Versionen aufrufen. Bei der Navigationsleiste mit drei Schaltflächen muss Window.setNavigationBarContrastEnforced auf false gesetzt werden, da sonst ein durchscheinender Scrim angewendet wird.

Transparente Systemleisten erstellen

So erstellen Sie eine durchscheinende Statusleiste:

  1. Aktualisieren Sie die androidx-core-Abhängigkeit auf 1.16.0-beta01 oder höher.
  2. Schließe dein XML-Layout in androidx.core.view.insets.ProtectionLayout ein und weise ihm eine ID zu.
  3. Greifen Sie programmatisch auf ProtectionLayout zu, um Schutzmaßnahmen festzulegen. Geben Sie dazu die Seite und eine GradientProtection für die Statusleiste an.

<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
            )
        )
    )

Achten Sie darauf, dass die ColorInt, die an GradientProtection übergeben wird, mit dem Hintergrund des Inhalts übereinstimmt. Beispiel: In einem Listendetail-Layout, das auf einem faltbaren Gerät angezeigt wird, können für den Listenbereich und den Detailbereich unterschiedliche GradientProtections mit unterschiedlichen Farben verwendet werden.

Abbildung 1. Schutz vor Farbverläufen in verschiedenen Farben.

Erstellen Sie keine durchscheinende Navigationsleiste für die Bedienung per Touch. So erstellen Sie eine durchscheinende Navigationsleiste mit drei Schaltflächen:

  • Wenn Ihr Layout bereits in einem ProtectionView umschlossen ist, können Sie der setProtections-Methode ein zusätzliches ColorProtection oder GradientProtection übergeben. Prüfen Sie vorher, ob window.isNavigationBarContrastEnforced = false.
  • Andernfalls legen Sie window.isNavigationBarContrastEnforced = true fest. Wenn Ihre App enableEdgeToEdge, window.isNavigationBarContrastEnforced = true aufruft, ist das die Standardeinstellung.

Weitere Tipps

Zusätzliche Tipps für die Arbeit mit Insets.

Scrollinhalte über die gesamte Breite anzeigen

Prüfe, ob das letzte Listenelement in deinem RecyclerView oder NestedScrollView durch die Systemleisten verdeckt wird. Dazu musst du Insets verarbeiten und clipToPadding auf false festlegen.

Im folgenden Video sehen Sie ein RecyclerView mit deaktivierter (links) und aktivierter (rechts) Edge-to-Edge-Anzeige:

Ein Codebeispiel finden Sie im Abschnitt Dynamische Listen mit RecyclerView erstellen.

Vollbild-Dialogfelder randlos anzeigen

Wenn Sie möchten, dass das Dialogfeld im Vollbildmodus von Rand zu Rand angezeigt wird, rufen Sie enableEdgeToEdge für das Dialogfeld auf.

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);
            }
        }
    }
    ...
}

Zusätzliche Ressourcen

Weitere Informationen zur Darstellung von Inhalten über die gesamte Breite des Bildschirms finden Sie in den folgenden Referenzen.

Blogs

Design

Weitere Dokumentation

Videos