Die Android-Plattform ist für das Zeichnen der System-UI verantwortlich, z. B. der Status- und Navigationsleiste. Diese System-UI wird unabhängig davon angezeigt, welche App der Nutzer verwendet. WindowInsets
liefert Informationen zur System-UI, damit Ihre App im richtigen Bereich gezeichnet wird und diese nicht von der System-UI verdeckt wird.
Standardmäßig ist die Benutzeroberfläche Ihrer Anwendung auf die System-UI wie die Statusleiste und die Navigationsleiste beschränkt. Dadurch wird sichergestellt, dass die Inhalte deiner App nicht von System-UI-Elementen verdeckt werden.
Wir empfehlen jedoch, Apps für die Anzeige in Bereichen zu aktivieren, in denen auch die System-UI angezeigt wird. Dadurch wird die Nutzererfahrung verbessert und deine App kann den verfügbaren Fensterbereich optimal nutzen. Auf diese Weise können Apps auch gemeinsam mit der System-UI animiert werden, insbesondere wenn die Softwaretastatur ein- und ausgeblendet wird.
Das Aktivieren der Anzeige in diesen Regionen und das Anzeigen von Inhalten hinter der System-UI wird als Edge-to-Edge-Angriff bezeichnet. Auf dieser Seite erfahren Sie mehr über die verschiedenen Arten von Einfügungen, wie Sie Edge-to-Edge-Funktionen aktivieren und wie Sie mit den eingefügten APIs Ihre Benutzeroberfläche animieren und vermeiden, dass Teile Ihrer App verdeckt werden.
Grundlagen
Bei Apps, die auf den neuesten Stand gebracht werden, müssen wichtige Inhalte und Interaktionen nicht von der System-UI verdeckt werden. Wenn sich beispielsweise eine Schaltfläche hinter der Navigationsleiste befindet, können Nutzer möglicherweise nicht darauf klicken.
Die Größe der System-UI und Informationen dazu, wo sie platziert wird, werden über Einsätze angegeben.
Jeder Teil der System-UI hat eine entsprechende Einfügungsart, die seine Größe und seine Platzierung beschreibt. Beispielsweise geben die Einfügungen für die Statusleiste die Größe und Position der Statusleiste an, während die Einfügungen für die Navigationsleiste die Größe und Position der Navigationsleiste angeben. Jede Art von Einfügung besteht aus vier Pixelmaßen: oben, links, rechts und unten. Diese Dimensionen geben an, wie weit die System-UI von den entsprechenden Seiten des App-Fensters entfernt ist. Damit eine Überlappung mit dieser Art von System-UI vermieden wird, muss die App-UI um diesen Wert eingegrenzt werden.
Diese integrierten Android-Einfügungstypen sind über WindowInsets
verfügbar:
Die Einsätze, die die Statusleisten beschreiben. Dies sind die oberen Leisten der System-UI mit Benachrichtigungssymbolen und anderen Anzeigen. |
|
Die Statusleistenelemente, die angeben, wann sie sichtbar sind. Wenn die Statusleisten derzeit ausgeblendet sind (aufgrund des Wechsels des immersiven Vollbildmodus), sind die Einsätze der Hauptstatusleiste leer, die Einfügungen jedoch nicht. |
|
Die Einsätze, die die Navigationsleisten beschreiben. Dies sind die System-UI-Leisten auf der linken, rechten oder unteren Seite des Geräts, die die Taskleiste oder die Navigationssymbole beschreiben. Diese können sich zur Laufzeit ändern, je nachdem, welche Navigationsmethode der Nutzer bevorzugt und wie er mit der Taskleiste interagiert. |
|
Die Navigationsleiste, die angibt, wann sie sichtbar sind. Wenn die Navigationsleisten derzeit ausgeblendet sind (aufgrund des Wechsels des immersiven Vollbildmodus), sind die Einfügungen der Hauptnavigationsleiste leer, aber diese Einfügungen sind nicht leer. |
|
Der Einsatz, der die Fenstergestaltung der System-UI beschreibt, wenn es sich um ein Freiformfenster handelt, z. B. die obere Titelleiste. |
|
Die Untertitelleiste zeigt an, wann sie sichtbar sind. Wenn die Untertitelleisten derzeit ausgeblendet sind, sind die Haupteinsätze der Untertitelleiste leer, aber diese Einsätze sind nicht leer. |
|
Die Kombination der Systemleistenelemente, einschließlich der Statusleisten, der Navigationsleisten und der Untertitelleiste. |
|
Die Systemleisten für den Zeitpunkt ihrer Sichtbarkeit. Wenn die Systemleisten derzeit ausgeblendet sind (aufgrund des Wechsels in den immersiven Vollbildmodus), sind die Einsätze der Hauptsystemleiste leer, aber diese Einfügungen sind nicht leer. |
|
Die Einsätze, die angeben, wie viel Platz die Softwaretastatur unten einnimmt. |
|
Einsätze, die angeben, wie viel Platz die Softwaretastatur vor der aktuellen Tastaturanimation eingenommen hat. |
|
Einsätze, die angeben, wie viel Platz die Softwaretastatur nach der aktuellen Tastaturanimation einnimmt. |
|
Eine Art von Einfügungen, die detailliertere Informationen über die Navigations-UI beschreiben. Sie geben an, wie viel Platz vom System und nicht von der App genutzt wird. Bei transparenten Navigationsleisten mit Gestennavigation können einige App-Elemente über die Benutzeroberfläche der Systemnavigation angetippt werden. |
|
Die Einfügungen für antippbare Elemente, wenn sie sichtbar sind. Wenn die antippbaren Elemente derzeit verborgen sind (aufgrund des Wechsels im immersiven Vollbildmodus), sind die Einsätze der antippbaren Elemente leer, die Einsätze sind jedoch nicht leer. |
|
Die Einsätze stellen die Anzahl der Einsätze dar, bei denen das System Gesten zur Navigation abfängt. Apps können die Verarbeitung einer begrenzten Anzahl dieser Touch-Gesten manuell über |
|
Eine Untergruppe der Touch-Gesten, die immer vom System ausgeführt werden und die nicht über |
|
Die Einfügungen, die den erforderlichen Abstand zur Vermeidung einer Überlappung mit einer Display-Aussparung (Einkerbung oder Nadelloch) darstellen. |
|
Die Einsätze, die die gebogenen Bereiche einer Wasserfall-Anzeige darstellen. Eine Wasserfall-Anzeige hat gekrümmte Bereiche entlang der Bildschirmränder, in denen sich der Bildschirm an die Seiten des Geräts wickelt. |
Diese Typen werden in drei „sicheren“ Einsätzen zusammengefasst, die dafür sorgen, dass Inhalte nicht verdeckt werden:
Diese „sicheren“ Einsätze schützen Inhalte auf unterschiedliche Weise, je nach den zugrunde liegenden Plattform-Einsätzen:
- Verwenden Sie
WindowInsets.safeDrawing
, um Inhalte zu schützen, die nicht unter einer System-UI dargestellt werden sollen. Dies ist die häufigste Verwendung von Einsätzen, um zu verhindern, dass Inhalte gezeichnet werden, die von der System-UI teilweise oder vollständig verdeckt werden. - Verwenden Sie
WindowInsets.safeGestures
, um Inhalte mit Touch-Gesten zu schützen. Dadurch wird verhindert, dass Systemgesten mit App-Gesten in Konflikt stehen, z. B. für Tabellenblätter am unteren Rand, Karussells oder in Spielen. - Verwende
WindowInsets.safeContent
in Kombination ausWindowInsets.safeDrawing
undWindowInsets.safeGestures
, damit es keine Überschneidungen beim Inhalt gibt.
Einrichtung von Einsätzen
Mit den folgenden Einrichtungsschritten können Sie Ihrer App die vollständige Kontrolle darüber geben, wo Inhalte abgerufen werden. Ohne diese Schritte zeichnet Ihre App möglicherweise schwarze oder einfarbige Farben hinter der System-UI oder wird nicht synchron mit der Softwaretastatur animiert.
- Rufen Sie
enableEdgeToEdge()
inActivity.onCreate
auf. Bei diesem Aufruf wird Ihre App hinter der System-UI angezeigt. Ihre App steuert dann, wie diese Einfügungen zum Anpassen der UI verwendet werden. Lege
android:windowSoftInputMode="adjustResize"
im EintragAndroidManifest.xml
deiner Aktivität fest. Mit dieser Einstellung kann Ihre App die Größe des Software-IME als Einsätze empfangen, mit denen Sie Inhalte entsprechend auffüllen und anordnen können, wenn der IME in Ihrer App erscheint und wieder verschwindet.<!-- in your AndroidManifest.xml file: --> <activity android:name=".ui.MainActivity" android:label="@string/app_name" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.MyApplication" android:exported="true">
APIs erstellen
Sobald Ihre Activity die Kontrolle über die Verarbeitung aller Einsätze übernommen hat, können Sie mit Compose APIs dafür sorgen, dass Inhalte nicht verdeckt werden und sich keine interaktiven Elemente mit der System-UI überschneiden. Diese APIs synchronisieren auch das Layout Ihrer Anwendung mit Einfügungsänderungen.
Dies ist beispielsweise die einfachste Methode, um die Einfügungen auf den Inhalt Ihrer gesamten Anwendung anzuwenden:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { Box(Modifier.safeDrawingPadding()) { // the rest of the app } } }
Dieses Snippet wendet die safeDrawing
-Fenstereinfügungen als Innenrand um den gesamten Inhalt der App an. Dadurch wird sichergestellt, dass sich die interaktiven Elemente nicht mit der System-UI überschneiden, bedeutet dies aber auch, dass die App nicht hinter die System-UI zieht, um einen randvollen Effekt zu erzielen. Damit Sie das gesamte Fenster optimal nutzen können, müssen Sie für jeden Bildschirm oder für die einzelnen Komponenten genau abstimmen, wo die Einfügungen angewendet werden.
Alle diese Einfügungstypen werden automatisch mit IME-Animationen animiert, die an API 21 zurückgesendet werden. Alle Layouts, die diese Werte enthalten, werden ebenfalls automatisch animiert, wenn sich die Werte für den Einsatz ändern.
Es gibt im Wesentlichen zwei Möglichkeiten, diese Einfügungstypen zum Anpassen Ihrer zusammensetzbaren Layouts zu verwenden: Modifikatoren für den Abstand und Einfügungsgrößenmodifikatoren.
Padding-Modifikatoren
Modifier.windowInsetsPadding(windowInsets: WindowInsets)
wendet die angegebenen Fenstereinfügungen als Innenrand an, genau wie Modifier.padding
.
Modifier.windowInsetsPadding(WindowInsets.safeDrawing)
wendet beispielsweise die sicheren Zeicheneinsätze als Abstand auf allen vier Seiten an.
Es gibt auch mehrere integrierte Dienstprogrammmethoden für die gängigsten Einfügungstypen.
Modifier.safeDrawingPadding()
ist eine solche Methode und entspricht Modifier.windowInsetsPadding(WindowInsets.safeDrawing)
. Für die anderen Einfügungstypen gibt es entsprechende Modifikatoren.
Eingesetzte Größenmodifikatoren
Mit den folgenden Modifikatoren wird eine bestimmte Anzahl von Fenstereinfügungen angewendet, indem die Größe der Komponente auf die Größe der Einfügungen festgelegt wird:
Wendet die Startseite von windowInsets als Breite an (z. B. |
|
Wendet die Endseite von windowInsets als Breite an (z. B. |
|
Wendet die obere Seite von windowInsets als Höhe an (z. B. |
|
|
Wendet die Unterseite von windowInsets als Höhe an (z. B. |
Diese Modifikatoren sind besonders nützlich, um die Größe eines Spacer
-Elements anzupassen, das den Platz der Einfügungen einnimmt:
LazyColumn( Modifier.imePadding() ) { // Other content item { Spacer( Modifier.windowInsetsBottomHeight( WindowInsets.systemBars ) ) } }
Eingefügter Verbrauch
Die eingefügten Padding-Modifikatoren (windowInsetsPadding
und Hilfsprogramme wie safeDrawingPadding
) nutzen automatisch den Teil der Einfügungen, der als Auffüllung angewendet wird. Verschachtelte Padding-Modifikatoren und Modifikatoren für die Größe von eingefügten Texten erkennen, dass ein Teil der Einfügungen bereits von äußeren Einfügungs-Modifikatoren konsumiert wurden. Bei genauerer Betrachtung des Kompositionsbaums wird vermieden, denselben Teil der Einsätze mehr als einmal zu verwenden, was zu viel zusätzlichen Platz bedeuten würde.
Eingefügte Größenmodifikatoren vermeiden außerdem, denselben Teil von Einsätzen mehr als einmal zu verwenden, wenn Einsätze bereits verarbeitet wurden. Da sie jedoch ihre Größe direkt ändern, verbrauchen sie keine Einsätze selbst.
Das führt dazu, dass bei verschachtelten Padding-Modifikatoren automatisch die auf jede zusammensetzbare Funktion angewendete Auffüllung geändert wird.
Im selben LazyColumn
-Beispiel wie zuvor wird die Größe von LazyColumn
durch den imePadding
-Modifikator geändert. Innerhalb von LazyColumn
hat das letzte Element die Höhe des unteren Rands der Systemleisten:
LazyColumn( Modifier.imePadding() ) { // Other content item { Spacer( Modifier.windowInsetsBottomHeight( WindowInsets.systemBars ) ) } }
Wenn der IME geschlossen ist, wendet der Modifikator imePadding()
keinen Innenrand an, da er keine Höhe hat. Da der imePadding()
-Modifikator keine Auffüllung anwendet, werden keine Einsätze verwendet. Die Höhe von Spacer
entspricht dann der Größe der unteren Seite der Systembalken.
Wenn der IME geöffnet wird, werden die IME-Einfügungen an die Größe des IME angepasst. Der imePadding()
-Modifikator beginnt mit dem unteren Innenrand, um die Größe des LazyColumn
beim Öffnen des IMEs anzupassen. Wenn der imePadding()
-Modifikator mit dem Anwenden des unteren Abstands beginnt, verbraucht er auch diese Anzahl von Einsätzen. Daher nimmt die Höhe von Spacer
ab, da ein Teil des Abstands für die Systembalken bereits durch den imePadding()
-Modifikator angewendet wurde. Wenn der imePadding()
-Modifikator einen unteren Abstand einfügt, der größer als die Systemleisten ist, ist die Höhe des Spacer
gleich null.
Wenn der IME geschlossen wird, erfolgen die Änderungen in umgekehrter Richtung: Der Spacer
beginnt sich ab einer Höhe von null zu erweitern, sobald der imePadding()
weniger als die Unterseite der Systemleisten angewendet wird. Sobald der IME vollständig animiert ist, entspricht der Spacer
schließlich der Höhe der unteren Seite der Systembalken.
Dieses Verhalten erfolgt über die Kommunikation zwischen allen windowInsetsPadding
-Modifikatoren und kann auf andere Weise beeinflusst werden.
Modifier.consumeWindowInsets(insets: WindowInsets)
verarbeitet ebenfalls Einsätze auf dieselbe Weise wie Modifier.windowInsetsPadding
, wendet jedoch die aufgenommenen Einsätze nicht als Auffüllung an. Dies ist in Kombination mit den Größenmodifikatoren nützlich, um gleichgeordnete Elemente darüber zu informieren, dass eine bestimmte Anzahl von Einsätzen bereits verbraucht wurde:
Column(Modifier.verticalScroll(rememberScrollState())) { Spacer(Modifier.windowInsetsTopHeight(WindowInsets.systemBars)) Column( Modifier.consumeWindowInsets( WindowInsets.systemBars.only(WindowInsetsSides.Vertical) ) ) { // content Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime)) } Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars)) }
Modifier.consumeWindowInsets(paddingValues: PaddingValues)
verhält sich ähnlich wie die Version mit einem WindowInsets
-Argument, aber zum Verarbeiten ist ein beliebiges PaddingValues
erforderlich. Dies ist nützlich, um Kinder zu informieren, wenn die Auffüllung oder der Abstand von einem anderen Mechanismus als den eingefügten Padding-Modifikatoren bereitgestellt wird, z. B. von einem gewöhnlichen Modifier.padding
oder Abstandshalter mit fester Höhe:
@OptIn(ExperimentalLayoutApi::class) Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) { // content Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime)) }
Wenn die Einsätze der unbearbeiteten Fenster ohne Verbrauch benötigt werden, verwenden Sie die WindowInsets
-Werte direkt oder WindowInsets.asPaddingValues()
, um einen PaddingValues
der Einsätze zurückzugeben, die vom Verbrauch nicht betroffen sind.
Aufgrund der folgenden Vorbehalte sollten Sie jedoch nach Möglichkeit immer die Padding-Modifizierer für Fenstereinsätze und die Größenmodifikatoren für Fenstereinfügungen verwenden.
Einsätze und Jetpack Compose-Phasen
Compose verwendet die zugrunde liegenden AndroidX Core APIs zum Aktualisieren und Animieren von Einsätzen, die die zugrunde liegenden Plattform-APIs zur Verwaltung von Einsätzen verwenden. Aufgrund dieses Plattformverhaltens haben Einsätze eine besondere Beziehung zu den Phasen von Jetpack Compose.
Die Werte der Einsätze werden nach der Zusammensetzungsphase, jedoch vor der Layoutphase aktualisiert. Das bedeutet, dass beim Lesen des Werts von Einfügungen in der Zusammensetzung im Allgemeinen ein Wert der Einsätze verwendet wird, der einen Frame zu spät ist. Die auf dieser Seite beschriebenen integrierten Modifikatoren werden so konzipiert, dass die Werte der Einfügungen bis zur Layoutphase verzögert verwendet werden. Dadurch wird sichergestellt, dass die eingefügten Werte im selben Frame verwendet werden, in dem sie aktualisiert werden.
Tastatur-IME-Animationen mit WindowInsets
Sie können Modifier.imeNestedScroll()
auf einen scrollbaren Container anwenden, um den IME automatisch zu öffnen und zu schließen, wenn zum Ende des Containers gescrollt wird.
class WindowInsetsExampleActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) WindowCompat.setDecorFitsSystemWindows(window, false) setContent { MaterialTheme { MyScreen() } } } } @OptIn(ExperimentalLayoutApi::class) @Composable fun MyScreen() { Box { LazyColumn( modifier = Modifier .fillMaxSize() // fill the entire window .imePadding() // padding for the bottom for the IME .imeNestedScroll(), // scroll IME at the bottom content = { } ) FloatingActionButton( modifier = Modifier .align(Alignment.BottomEnd) .padding(16.dp) // normal 16dp of padding for FABs .navigationBarsPadding() // padding for navigation bar .imePadding(), // padding for when IME appears onClick = { } ) { Icon(imageVector = Icons.Filled.Add, contentDescription = "Add") } } }
Abbildung 1: IME-Animationen
Unterstützung für Material 3-Komponenten
Der Einfachheit halber werden bei vielen der integrierten „Material 3 Composables“ (androidx.compose.material3
) Einsätze verwendet, je nachdem, wie die zusammensetzbaren Funktionen gemäß den Material-Spezifikationen in Ihrer App platziert werden.
Einfügung für zusammensetzbare Funktionen
Nachfolgend finden Sie eine Liste der Materialkomponenten, die Einsätze automatisch verarbeiten.
App-Leisten
TopAppBar
/SmallTopAppBar
/CenterAlignedTopAppBar
/MediumTopAppBar
/LargeTopAppBar
: Hierdurch werden die oberen und horizontalen Seiten der Systemleisten als Innenrand angewendet, da sie oben im Fenster verwendet werden.BottomAppBar
: Damit werden die unteren und horizontalen Seiten der Systemleisten als Innenrand verwendet.
Inhaltscontainer
ModalDrawerSheet
/DismissibleDrawerSheet
/PermanentDrawerSheet
(Inhalt in einer modalen Navigationsleiste): Wendet die Einsätze Vertikal und Start auf den Inhalt an.ModalBottomSheet
: Wendet die untersten Einsätze an.NavigationBar
: Wendet die Einsätze unten und horizontal an.NavigationRail
: Wendet die Einsätze Vertical und start an.
Gerüst
Standardmäßig stellt Scaffold
Werte als Parameter paddingValues
zur Verfügung, die Sie verwenden und verwenden können.
Scaffold
wendet die Einsätze nicht auf Inhalte an. Sie sind dafür verantwortlich.
So können Sie beispielsweise diese Einfügungen mit einem LazyColumn
in einem Scaffold
verwenden:
Scaffold { innerPadding -> // innerPadding contains inset information for you to use and apply LazyColumn( // consume insets as scaffold doesn't do it by default modifier = Modifier.consumeWindowInsets(innerPadding), contentPadding = innerPadding ) { items(count = 100) { Box( Modifier .fillMaxWidth() .height(50.dp) .background(colors[it % colors.size]) ) } } }
Standardeinsätze überschreiben
Sie können das Verhalten der zusammensetzbaren Funktion konfigurieren, indem Sie den an die zusammensetzbaren Funktion übergebenen Parameter windowInsets
ändern. Dieser Parameter kann eine andere Art von Fenstereinsatz sein, der stattdessen angewendet werden soll, oder er wird deaktiviert, indem eine leere Instanz übergeben wird: WindowInsets(0, 0, 0, 0)
.
Wenn Sie beispielsweise die Verarbeitung von Platzhaltern für LargeTopAppBar
deaktivieren möchten, setzen Sie den Parameter windowInsets
auf eine leere Instanz:
LargeTopAppBar( windowInsets = WindowInsets(0, 0, 0, 0), title = { Text("Hi") } )
Interoperabilität mit den Systemeinsätzen „View“
Möglicherweise müssen Sie Standardeinfügungen überschreiben, wenn sich auf Ihrem Bildschirm sowohl Ansichten als auch Code in einer Hierarchie befinden. In diesem Fall müssen Sie genau angeben, in welcher Version die Einfügungen aufgenommen und in welchen ignoriert werden sollen.
Wenn Ihr äußerstes Layout beispielsweise ein Android View-Layout ist, sollten Sie die Einfügungen im View-System verwenden und für Compose ignorieren.
Wenn Ihr äußerstes Layout eine zusammensetzbare Funktion ist, sollten Sie die Einfügungen in Compose verwenden und die AndroidView
-zusammensetzbaren Funktionen entsprechend auffüllen.
Standardmäßig nutzt jeder ComposeView
alle Einsätze auf der Verbrauchsebene WindowInsetsCompat
. Wenn Sie dieses Standardverhalten ändern möchten, setzen Sie ComposeView.consumeWindowInsets
auf false
.
Ressourcen
- Jetzt in Android: Eine voll funktionsfähige Android-App, die vollständig mit Kotlin und Jetpack Compose erstellt wurde.
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Materialkomponenten und Layouts
CoordinatorLayout
zum Schreiben migrieren- Weitere Überlegungen