Inhalte in Ansichten randlos anzeigen

Jetpack Compose ausprobieren
Jetpack Compose ist das empfohlene UI-Toolkit für Android. Informationen zum Arbeiten mit der randlosen Anzeige in Compose

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

Viele Apps haben eine obere App-Leiste. Die obere App-Leiste sollte sich bis zum oberen Rand des Bildschirms 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 Leisten sollten sich ebenfalls bis zum unteren Rand des Bildschirms erstrecken und hinter der Navigationsleiste angezeigt werden. Andernfalls sollten Apps scrollbare Inhalte hinter der Navigationsleiste anzeigen.

Abbildung 1 Systemleisten in einem randlosen Layout.

Beachten Sie bei der Implementierung eines randlosen Layouts in Ihrer App Folgendes:

  1. Randlose Anzeige aktivieren
  2. Adaptive Layouts implementieren, um die Nutzererfahrung auf verschiedenen Formfaktoren zu optimieren
  3. Visuelle Überlappungen verarbeiten
  4. Überlegen Sie, ob Sie hinter den Systemleisten Scrims anzeigen möchten.
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 randlose Anzeige in früheren Android-Versionen aktivieren möchten, rufen Sie enableEdgeToEdge in onCreate Ihrer 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. Eine Ausnahme ist der Bedienung über 3 Buttons-Navigationsmodus, in dem die Navigationsleiste einen durchscheinenden Scrim erhält. Die Farben der Systemsymbole und des Scrim werden an das helle oder dunkle Design des Systems angepasst.

Informationen zum Aktivieren der randlosen Anzeige in Ihrer App ohne Verwendung der enableEdgeToEdge() Funktion finden Sie unter Randlose Anzeige manuell einrichten.

Überlappungen mit Insets verarbeiten

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

Sie können Überlappungen beheben, indem Sie auf Insets reagieren. Diese geben an, welche Teile des Bildschirms sich mit der System-UI überschneiden, z. B. mit der Navigationsleiste oder der Statusleiste. Überschneidungen können bedeuten, dass Inhalte über dem Inhalt angezeigt werden, aber sie können Ihre App auch über Systemgesten informieren.

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

  • Systemleisten-Insets:Am besten für Ansichten geeignet, die anklickbar sind und nicht visuell von den Systemleisten verdeckt werden dürfen.

  • Display-Aussparungs-Insets:Für Bereiche, in denen aufgrund der Form des Geräts eine Display-Aussparung vorhanden sein kann.

  • Systemgesten-Insets:Für Bereiche der Gestensteuerung, die vom System verwendet werden und Vorrang vor Ihrer App haben.

Systemleisten-Insets

Systemleisten-Insets sind die am häufigsten verwendete Art von 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 anklickbare Ansichten in Ihrer App zu verschieben oder mit Innenabstand zu versehen, die nicht visuell von den Systemleisten verdeckt werden dürfen.

In Abbildung 3 wird beispielsweise der unverankerte Aktions button (Floating Action Button, FAB) teilweise von der Navigationsleiste verdeckt:

Beispiel für die Edge-to-Edge-Implementierung, bei der die Navigationsleiste das FAB verdeckt
Abbildung 3 Navigationsleiste, die einen FAB in einem randlosen Layout überlappt.

Um diese Art von visueller Überlappung im Touchgesten- 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 Sie Systemleisten-Insets implementieren:

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 Überlappung, wie in Abbildung 4 dargestellt:

Eine durchscheinende Navigationsleiste, die das Aktionsschaltfläche nicht verdeckt
Abbildung 4 : Visuelle Überlappung im Schaltflächen Modus beheben.

Dasselbe gilt für den Modus der Gestensteuerung, wie in Abbildung 5 dargestellt:

randloses Display mit Bedienung über Gesten
Abbildung 5 Visuelle Überlappung im Gesten-Navigationsmodus beheben.

Display-Aussparungs-Insets

Einige Geräte haben Display-Aussparungen. In der Regel befindet sich die Aussparung oben auf dem Bildschirm und ist in der Statusleiste enthalten. Wenn sich der Gerätebildschirm im Querformat befindet, kann sich die Aussparung am vertikalen Rand befinden. Je nachdem, welche Inhalte Ihre App auf dem Bildschirm anzeigt, sollten Sie Innenabstand implementieren, um Display-Aussparungen zu vermeiden. Standardmäßig werden Apps in der Display-Aussparung angezeigt.

Viele App-Bildschirme zeigen beispielsweise eine Liste von Elementen. Listen Sie Elemente nicht mit der Display-Aussparung oder den Systemleisten auf.

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 logische oder-Verknüpfung der Systemleisten- und Display-Aussparungstypen verwenden.

Setzen Sie clipToPadding auf RecyclerView, damit der Innenabstand mit den Listenelementen gescrollt wird. So können die Elemente beim Scrollen des Nutzers hinter den Systemleisten angezeigt werden, wie im folgenden Beispiel dargestellt.

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

Systemgesten-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 Überlappungen mit den Systemgesten-Insets vermeiden, getInsets(int) mit WindowInsetsCompat.Type.systemGestures().

Verwenden Sie diese Insets, um wischbare Ansichten von den Rändern zu verschieben oder mit Innenabstand zu versehen. Häufige Anwendungsfälle sind Bottom Sheets, Wischen in Spielen und Karussells, die mit ViewPager2 implementiert wurden.

In Android 10 oder höher enthalten Systemgesten-Insets ein unteres Inset für die Home-Geste und ein linkes und rechtes Inset für die Zurück-Gesten:

Beispiel für die Messungen des Insets für Systemgesten
Abbildung 7 : Messungen für Systemgesten-Insets.

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-Materialkomponenten (com.google.android.material) verarbeiten Insets automatisch, darunter 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 Verarbeiten von Insets mit Materialkomponenten in Compose

Abwärtskompatible Inset-Verteilung

Wenn Sie die Verteilung von Insets an untergeordnete Ansichten beenden und zu viel Innenabstand vermeiden möchten, können Sie Insets mit der WindowInsetsCompat.CONSUMED Konstante verarbeiten. Auf Geräten mit Android 10 (API-Level 29 und niedriger) werden Insets jedoch nicht an gleichgeordnete Elemente verteilt, nachdem WindowInsetsCompat.CONSUMED aufgerufen wurde. Dies kann zu unbeabsichtigten visuellen Überlappungen führen.

Beispiel für fehlerhaftes Inset-Dispatching
Abbildung 8. Beispiel für eine fehlerhafte Inset-Verteilung. Insets werden nicht an gleichgeordnete Ansichten verteilt, nachdem ViewGroup 1 Insets in Android 10 (API-Level 29) und niedriger verarbeitet hat. Dadurch überlappt TextView 2 mit der Systemnavigationsleiste. In Android 11 (API-Level 30) und höher werden Insets jedoch wie erwartet an gleichgeordnete Ansichten verteilt.

Wenn Sie bestätigen möchten, dass Insets für alle unterstützten Android Versionen an gleichgeordnete Elemente verteilt werden, verwenden Sie ViewGroupCompat#installCompatInsetsDispatch, bevor Sie Insets verarbeiten. 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 : Korrigierte Inset-Verteilung nach dem Aufrufen von ViewGroupCompat#installCompatInsetsDispatch.

Immersiver Modus

Einige Inhalte lassen sich am besten im Vollbildmodus ansehen, um dem Nutzer ein noch intensiveres Erlebnis zu bieten. Sie können die Systemleisten für den immersiven Modus mit den WindowInsetsController und WindowInsetsControllerCompat Bibliotheken 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 immersiven Modus ausblenden.

Systemleistensymbole

Wenn Sie enableEdgeToEdge aufrufen, werden die Farben der Systemleistensymbole aktualisiert, wenn sich das Design des Geräts ändert.

Bei der randlosen Anzeige müssen Sie möglicherweise die Farben der Systemleistensymbole 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);

Systemleistenschutz

Sobald Ihre App auf SDK 35 oder höher ausgerichtet ist, wird die randlose Anzeige erzwungen. Die Systemstatusleiste und die Navigationsleisten für die Bedienung über Gesten sind transparent, die Navigationsleiste mit drei Schaltflächen ist jedoch durchscheinend. Rufen Sie enableEdgeToEdge auf, um dies abwärtskompatibel zu machen.

Die Systemstandardeinstellungen funktionieren jedoch möglicherweise nicht für alle Anwendungsfälle. In den Designrichtlinien für Android-Systemleisten und Randloses Design erfahren Sie, ob Sie transparente oder durchscheinende Systemleisten verwenden sollten.

Transparente Systemleisten erstellen

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

Erstellen Sie eine transparente Navigationsleiste für die Bedienung über Gesten, indem Sie auf Android 15 oder höher ausrichten oder enableEdgeToEdge() mit Standardargumenten für frühere Versionen aufrufen. Setzen Sie für die Navigationsleiste mit drei Schaltflächen Window.setNavigationBarContrastEnforced auf false. Andernfalls wird ein durchscheinender Scrim angewendet.

Durchscheinende Systemleisten erstellen

So erstellen Sie eine durchscheinende Statusleiste:

  1. Aktualisieren Sie Ihre androidx-core Abhängigkeit auf 1.16.0-beta01 oder höher.
  2. Umschließen Sie Ihr XML-Layout mit androidx.core.view.insets.ProtectionLayout und weisen Sie eine ID zu.
  3. Greifen Sie programmatisch auf die ProtectionLayout zu, um Schutzmaßnahmen festzulegen. Geben Sie die Seite und einen 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-Farbe, die an GradientProtection übergeben wird, mit dem Hintergrund des Inhalts übereinstimmt. Bei einem Layout mit Listen-Detailansicht, das auf einem faltbaren Gerät angezeigt wird, können beispielsweise unterschiedliche GradientProtections mit unterschiedlichen Farben für den Listenbereich und den Detailbereich verwendet werden.

Abbildung 1 Farbverlaufsschutz in verschiedenen Farben.

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

  • Wenn Ihr Layout bereits in ProtectionView umschlossen ist, können Sie der Methode setProtections einen zusätzlichen ColorProtection oder GradientProtection übergeben. Achten Sie vorher darauf, dass window.isNavigationBarContrastEnforced = false ist.
  • Andernfalls setzen Sie window.isNavigationBarContrastEnforced = true.

Weitere Tipps

Zusätzliche Tipps zur Verarbeitung von Insets.

Scrollbare Inhalte randlos anzeigen

Achten Sie darauf, dass das letzte Listenelement in RecyclerView oder NestedScrollView nicht von den Systemleisten verdeckt wird. Verarbeiten Sie dazu Insets und setzen Sie clipToPadding auf false.

Im folgenden Video wird ein RecyclerView mit deaktivierter (links) und aktivierter (rechts) randloser Anzeige gezeigt:

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

Vollbilddialogfelder randlos anzeigen

Wenn Sie Vollbilddialogfelder randlos anzeigen möchten, rufen Sie enableEdgeToEdge im 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 randlosen Anzeige finden Sie in den folgenden Referenzen.

Blogs

Design

Weitere Dokumentation

Videos