Fenstereinfügungen in Compose

Die Android-Plattform ist für das Zeichnen der System-UI verantwortlich, z. B. der Statusleiste und der Navigationsleiste. Diese System-UI wird unabhängig davon angezeigt, die der Nutzer verwendet.

WindowInsets stellt Informationen zum System bereit. Benutzeroberfläche, um sicherzustellen, dass Ihre App im richtigen Bereich gezeichnet wird und nicht verdeckt wird über die System-UI.

<ph type="x-smartling-placeholder">
</ph> Von Rand zu Rand, um hinter den Systembalken zu zeichnen
Abbildung 1: Sie gehen randlos, um hinter den Systemleisten zu zeichnen.

Unter Android 14 (API-Level 34) und niedriger wird die UI Ihrer App nicht darunter dargestellt. Systemleisten und Display-Aussparungen standardmäßig.

Unter Android 15 (API-Level 35) und höher wird Ihre App unter dem System angezeigt Balken und Display-Aussparungen, sobald Ihre App auf SDK 35 ausgerichtet ist. Dies führt zu einer nahtlose User Experience und ermöglicht es Ihrer App, die Fensterfläche verfügbar ist.

Das Darstellen von Inhalten hinter der System-UI wird als Edge-to-Edge bezeichnet. Auf diesem erfahren Sie mehr über die verschiedenen Einsatzarten, und wie Sie mithilfe der eingefügten APIs Ihre Benutzeroberfläche animieren und sicherstellen können, dass die Inhalte Ihrer App nicht durch System-UI-Elemente verdeckt wird.

Eingefügte Grundlagen

Bei der neuesten Entwicklung einer App müssen Sie dafür sorgen, dass wichtige Inhalte und Interaktionen werden von der System-UI nicht verdeckt. Wenn eine Schaltfläche beispielsweise hinter der Navigationsleiste platziert, können Nutzende sie möglicherweise nicht anklicken.

Die Größe der System-Benutzeroberfläche und Informationen zum Speicherort werden angegeben. über insets.

Jeder Teil der System-UI hat einen entsprechenden Einsatztyp, der beschreibt, und wo es platziert wird. Statusleisten-Einfügungen liefern beispielsweise die Größe und die Position der Statusleiste, während die Navigationsleisten Größe und Position der Navigationsleiste. Jede Art von Einfügung besteht aus vier Pixelabmessungen: oben, links, rechts und unten. Diese Dimensionen geben an, erweitert sich die System-UI von den entsprechenden Seiten des App-Fensters aus. Um dies zu vermeiden mit dieser Art von System-UI überschneidet. Daher muss die Anwendungs-UI von diesem Betrag.

Die folgenden integrierten Android-Einfügungstypen sind über WindowInsets verfügbar:

WindowInsets.statusBars

Die Einfügungen zur Beschreibung der Statusleisten. Dies sind die oberen System-UI-Leisten mit Benachrichtigungssymbolen und anderen Indikatoren.

WindowInsets.statusBarsIgnoringVisibility

Die Statusleisteneinfügungen für den Zeitpunkt, zu dem sie sichtbar sind. Wenn die Statusleisten derzeit ausgeblendet sind (aufgrund des immersiven Vollbildmodus), sind die Haupteinfügungen der Statusleiste leer. Diese Einfügungen sind jedoch nicht leer.

WindowInsets.navigationBars

Die Einfügungen zur Beschreibung der Navigationsleisten. Dies sind die System-UI-Leisten auf der linken, rechten oder unteren Seite des Geräts, die die Taskleiste oder Navigationssymbole beschreiben. Diese können sich zur Laufzeit je nach bevorzugter Navigationsmethode des Nutzers und Interaktion mit der Taskleiste ändern.

WindowInsets.navigationBarsIgnoringVisibility

Die Navigationsleisteneinfügungen für den Zeitpunkt, an dem sie sichtbar sind. Wenn die Navigationsleisten derzeit ausgeblendet sind (aufgrund des immersiven Vollbildmodus), sind die Einfügungen der Hauptnavigationsleiste leer, aber diese Einfügungen sind nicht leer.

WindowInsets.captionBar

Die Einfügung, die die Fenstergestaltung der System-UI beschreibt, wenn sie sich in einem freien Fenster befindet, z. B. in der oberen Titelleiste.

WindowInsets.captionBarIgnoringVisibility

Die Untertitelleiste wird eingeblendet, wenn sie sichtbar ist. Wenn die Untertitelleisten derzeit ausgeblendet sind, sind die Einfügungen der Hauptuntertitelleiste leer, aber diese Einfügungen sind nicht leer.

WindowInsets.systemBars

Die Gesamtheit der Systemleisten-Einfügungen, einschließlich der Statusleisten, Navigationsleisten und der Untertitelleiste.

WindowInsets.systemBarsIgnoringVisibility

Die Systemleisteneinfügungen für den Zeitpunkt, an dem sie sichtbar sind. Wenn die Systemleisten derzeit ausgeblendet sind (aufgrund des immersiven Vollbildmodus), sind die Haupteinfügungen der Systemleiste leer. Diese Einfügungen sind jedoch nicht leer.

WindowInsets.ime

Die Einsätze, die angeben, wie viel Platz die Softwaretastatur unten einnimmt.

WindowInsets.imeAnimationSource

Die Einfügungen, die den Platz beschreiben, den die Softwaretastatur vor der aktuellen Tastaturanimation eingenommen hat.

WindowInsets.imeAnimationTarget

Die Einfügungen, die den Platz beschreiben, den die Softwaretastatur nach der aktuellen Tastaturanimation einnimmt.

WindowInsets.tappableElement

Art von Einsätzen, die detailliertere Informationen zur Navigationsbenutzeroberfläche beschreiben, die den Platz angeben, an dem „getippt“ wird vom System und nicht von der App verarbeitet. Bei transparenten Navigationsleisten mit Gestensteuerung können einige App-Elemente über die Benutzeroberfläche der Systemsteuerung angetippt werden.

WindowInsets.tappableElementIgnoringVisibility

Die antippbaren Elementeinsätze, die sichtbar sind. Wenn die antippbaren Elemente derzeit ausgeblendet sind (aufgrund des immersiven Vollbildmodus), sind die Haupteinfügungen der antippbaren Elemente leer. Diese Einfügungen sind jedoch nicht leer.

WindowInsets.systemGestures

Die Einfügungen, die die Anzahl der Einfügungen darstellen, bei denen das System Gesten zur Navigation abfängt. Apps können die Verarbeitung einer begrenzten Anzahl dieser Touch-Gesten über Modifier.systemGestureExclusion manuell festlegen.

WindowInsets.mandatorySystemGestures

Eine Untergruppe der Systemgesten, die immer vom System ausgeführt werden und die nicht über Modifier.systemGestureExclusion deaktiviert werden können.

WindowInsets.displayCutout

Die Einsätze, die den Abstand darstellen, der erforderlich ist, um eine Überlappung mit einer Display-Aussparung (Kerbe oder Nadelloch) zu vermeiden.

WindowInsets.waterfall

Die Einsätze, die die gekrümmten Bereiche einer Wasserfalldarstellung darstellen. Bei einer Wasserfalldarstellung gibt es gebogene Bereiche entlang der Displayränder, an denen sich der Bildschirm entlang der Seiten des Geräts zusammenzieht.

Diese Typen werden durch drei „sichere“ Einsatztypen, mit denen sichergestellt wird, Ausgeblendet:

Diese „sicheren“ Verschiedene eingefügte Typen schützen Inhalte auf unterschiedliche Weise, zugrunde liegende Plattform-Einsätze:

  • Mit WindowInsets.safeDrawing können Sie Inhalte schützen, die nicht gezeichnet werden sollen unterhalb der System-UI angezeigt. Dies ist die gängigste Verwendung von Insets: um zu verhindern, die von der Systembenutzeroberfläche verdeckt werden (entweder teilweise oder vollständig).
  • Verwenden Sie WindowInsets.safeGestures, um Inhalte mit Gesten zu schützen. Dieses vermeidet, dass System-Touch-Gesten mit App-Gesten in Konflikt stehen (z. B. für die unteren Tabellenblätter, Karussells oder in Spielen).
  • WindowInsets.safeContent mit einer Kombination aus WindowInsets.safeDrawing und WindowInsets.safeGestures, um sicherzustellen, Der Inhalt weist keine visuelle Überschneidung oder Gesteinsüberschneidung auf.

Einrichtung von Einsätzen

Um Ihrer App die volle Kontrolle darüber zu geben, wo sie Inhalte abruft, führen Sie die folgenden Einstellungen aus Schritte. Ohne diese Schritte zeichnet Ihre App möglicherweise schwarze oder leuchtende Farben hinter dem System-UI oder nicht synchron mit der Softwaretastatur animiert werden.

  1. Wählen Sie SDK 35 oder höher aus, um unter Android 15 und höher Edge-to-Edge zu erzwingen. Ihre App hinter der System-UI angezeigt. Sie können die Benutzeroberfläche Ihrer App anpassen, indem Sie Einsätze.
  2. Rufen Sie optional enableEdgeToEdge() in Activity.onCreate(), mit dem deine App gegenüber vorherigen Android-Versionen
  3. Du kannst android:windowSoftInputMode="adjustResize" in deinen Aktivitäten festlegen: AndroidManifest.xml-Eintrag. Mit dieser Einstellung kann Ihre App die Größe des Software-IMEs als Insets aus, mit denen du Inhalte auffüllen und anordnen kannst. wenn der IME in der 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">
    

Compose-APIs

Sobald Ihre Aktivität die Verwaltung aller Insets übernommen hat, können Sie die Funktion "Schreiben" verwenden. APIs, die dafür sorgen, dass Inhalte nicht verdeckt werden und interagierbare Elemente nicht mit der System-UI überschneidet. Diese APIs synchronisieren auch das Layout Ihrer App mit kleine Änderungen.

Dies ist beispielsweise die einfachste Methode, der gesamten App:

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

    enableEdgeToEdge()

    setContent {
        Box(Modifier.safeDrawingPadding()) {
            // the rest of the app
        }
    }
}

Dieses Snippet wendet die safeDrawing-Fenstereinsätze als Innenrand um den den gesamten Inhalt der App. So wird sichergestellt, dass interaktive Elemente sich mit der System-UI überschneidet, bedeutet dies auch, dass keine der Apps der Benutzeroberfläche des Systems, um einen Edge-to-Edge-Effekt zu erzielen. Um das gesamte Leistungsspektrum müssen Sie für jeden Bildschirm genau festlegen, wo die Insets angewendet werden. oder Komponente für Komponente.

Alle diese Einsatztypen werden automatisch mit IME-Animationen animiert. zu API 21 zurückportiert werden. Alle Layouts, in denen diese Einfügungen verwendet werden, automatisch animiert, wenn sich die eingefügten Werte ändern.

Es gibt zwei Möglichkeiten, wie Sie mit diesen eingefügten Typen Ihre Composable- Layouts: Modifikatoren für Innenrand und Größe für eingefügte Elemente

Modifikatoren für das Padding

Modifier.windowInsetsPadding(windowInsets: WindowInsets) wendet die vorgegebenen Fenstereinfügungen als Abstand und verhält sich dann genauso wie Modifier.padding. Beispielsweise gilt Modifier.windowInsetsPadding(WindowInsets.safeDrawing) die sicheren Zeicheneinsätze als Abstände auf allen vier Seiten.

Es gibt auch mehrere integrierte Dienstprogrammmethoden für die gängigsten Einsatztypen. Modifier.safeDrawingPadding() ist eine solche Methode, entspricht Modifier.windowInsetsPadding(WindowInsets.safeDrawing). Es gibt vergleichbare Modifikatoren für die anderen Einsatztypen.

Eingefügte Größenmodifikatoren

Die folgenden Modifikatoren wenden eine Menge an Fenstereinfügungen an, indem sie die Größe der für die Komponente die Größe der Einsätze fest:

Modifier.windowInsetsStartWidth(windowInsets: WindowInsets)

Wendet die Anfangsseite von windowInsets auf die Breite an (z. B. Modifier.width)

Modifier.windowInsetsEndWidth(windowInsets: WindowInsets)

Wendet die Endeseite von windowInsets auf die Breite an (z. B. Modifier.width)

Modifier.windowInsetsTopHeight(windowInsets: WindowInsets)

Wendet die obere Seite von windowInsets als Höhe an (z. B. Modifier.height)

Modifier.windowInsetsBottomHeight(windowInsets: WindowInsets)

Wendet die Unterseite von windowInsets auf die Höhe an (z. B. Modifier.height)

Diese Modifikatoren sind besonders nützlich für die Größe von Spacer, die den Platz der Einsätze:

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

Verbrauch

Die Modifikatoren für den eingefügten Abstand (windowInsetsPadding und Hilfsfunktionen wie safeDrawingPadding) automatisch den Teil der Einfügungen verbrauchen, die wird als Abstand angewendet. Während Sie tiefer in den Kompositionsbaum vordringen, Padding-Modifikatoren und die eingefügten Größenmodifikatoren wissen, dass ein Teil des Einsätze wurden bereits von Modifikatoren für äußere Einfügungen verarbeitet. Vermeiden Sie mehr als einmal verwendet, was zu einer höheren viel zusätzlichen Platz.

Mit Modifikatoren für eingefügte Größen können Sie verhindern, dass ein Teil der Einfügungen mehr als einmal verwendet wird. falls bereits Insets aufgebraucht sind. Da sie jedoch ihre verwenden, verbrauchen sie selbst keine Einsätze.

Infolgedessen ändern verschachtelte Padding-Modifikatoren automatisch die Menge der auf jede zusammensetzbare Funktion angewendet.

Im gleichen LazyColumn-Beispiel wie zuvor wird die LazyColumn durch den imePadding-Modifikator in der Größe angepasst. In der LazyColumn ist das letzte Element an die Höhe des unteren Rands der Systemleisten angepasst:

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

Wenn der IME geschlossen wird, wendet der imePadding()-Modifikator keinen Abstand an, da hat der IME keine Höhe. Da für den imePadding()-Modifikator kein Padding angewendet wird, werden keine Insets verbraucht und die Höhe von Spacer entspricht der Größe an der Unterseite der Systemleisten.

Wenn der IME geöffnet wird, werden die IME-Einfügungen so animiert, dass sie der Größe des IME entsprechen. Der imePadding()-Modifikator wendet jetzt einen Abstand unten an, um die Größe von LazyColumn, wenn der IME geöffnet wird. Wenn der imePadding()-Modifikator angewendet wird wird diese Anzahl von Einsätzen verbraucht. Daher entspricht der Parameter Die Höhe von Spacer nimmt als Teil des Abstands für das System zu. Balken wurde bereits mit dem imePadding()-Modifikator angewendet. Sobald die Der imePadding()-Modifikator wendet einen größeren Abstand unten an als die Systembalken, ist die Höhe von Spacer null.

Wenn der IME geschlossen wird, erfolgen die Änderungen umgekehrt: Der Spacer beginnt, wird von einer Höhe von 0 aus maximiert, sobald imePadding() weniger angewendet wird als die der Systembalken, bis Spacer schließlich der Höhe des der Systemleisten, sobald der IME vollständig animiert ist.

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
Abbildung 2: Edge-to-Edge-Lazy Column mit TextField.

Dieses Verhalten wird durch die Kommunikation zwischen allen windowInsetsPadding-Modifikatoren und kann durch einige andere Faktoren beeinflusst werden. .

Modifier.consumeWindowInsets(insets: WindowInsets) verbraucht auch Einsätze wie für Modifier.windowInsetsPadding, sie gilt jedoch nicht für die aufgenommenen Einsätze als Padding. Dies ist in Kombination mit dem Einsatz Größenmodifikatoren, um Geschwistern anzuzeigen, dass eine bestimmte Anzahl von Einsätzen bereits verbraucht:

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 sehr gut ähnlich wie bei der Version mit einem WindowInsets-Argument, beliebige PaddingValues abrufen. Dies ist nützlich, um untergeordneten Elementen, wenn der Abstand oder die Abstände durch einen anderen Mechanismus als die Modifikatoren für eingefügten Abstand, z. B. ein gewöhnliches Modifier.padding oder eine feste Höhe Abstandshalter:

@OptIn(ExperimentalLayoutApi::class)
Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) {
    // content
    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
}

Wenn die Rohfenstereinfügungen ohne Verbrauch benötigt werden, verwenden Sie die Methode WindowInsets-Werte direkt oder verwenden Sie WindowInsets.asPaddingValues() für PaddingValues der Insets zurückgeben, die vom Verbrauch nicht betroffen sind. Aufgrund der nachfolgenden Vorbehalte sollte jedoch die Verwendung des Paddings für Fenstereinschnitte vorgezogen werden. Modifikatoren und Fenstereinfügungen Größenmodifikatoren wann immer möglich.

Phasen der Insets und Jetpack Compose-Phasen

Compose verwendet die zugrunde liegenden AndroidX Core APIs, um Einfügungen zu aktualisieren und zu animieren. die die zugrunde liegenden Plattform-APIs nutzen, die Einsätze verwalten. Aufgrund dieser Plattform Insets haben eine besondere Beziehung zu den Phasen von Jetpack. Schreiben:

Die Werte der Insets werden nach der Erstellungsphase, aber vor den Änderungen aktualisiert. Layoutphase. Das bedeutet, dass das Lesen des Werts von Insets in der Zusammensetzung verwendet im Allgemeinen einen Wert der Insets, der einen Frame zu spät kommt. Die integrierte Die auf dieser Seite beschriebenen Modifikatoren sind so konzipiert, dass sie mit den Werten der bis zur Layoutphase ein, wodurch sichergestellt wird, dass die eingefügten Werte wie sie aktualisiert werden.

Tastatur-IME-Animationen mit WindowInsets

Sie können Modifier.imeNestedScroll() auf einen scrollbaren Container anwenden, um wird der IME automatisch geschlossen, wenn Sie an das Ende des Containers scrollen.

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

<ph type="x-smartling-placeholder">
</ph> Animation eines UI-Elements, das nach oben und unten scrollt, um Platz für eine Tastatur zu schaffen
Abbildung 3: IME-Animationen.

Eingefügte Unterstützung für Material 3-Komponenten

Für eine einfachere Bedienung gibt es viele der (androidx.compose.material3) Einsatzfelder selbst verarbeiten, je nachdem, wie die zusammensetzbaren Funktionen in Ihrer App platziert sind. gemäß den Materialspezifikationen.

Zusammensetzbare Funktionen für eingefügte Verarbeitung

Nachfolgend finden Sie eine Liste der Materialien Komponenten, die automatische Bearbeitung von Einsätzen.

App-Leisten

Inhaltscontainer

Gerüst

Standardmäßig Scaffold stellt Einfügungen als Parameter paddingValues bereit, die Sie nutzen und verwenden können. Scaffold wendet die Einfügungen nicht auf Inhalte an. die Verantwortung liegt ganz bei Ihnen. So verwenden Sie beispielsweise diese Einfügungen mit einem LazyColumn in einem Scaffold:

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

Standard-Einfügungen überschreiben

Sie können den windowInsets-Parameter, der an die zusammensetzbare Funktion übergeben wird, ändern, konfigurieren Sie das Verhalten der zusammensetzbaren Funktion. Dieser Parameter kann ein anderer Fenstereinsatz, der stattdessen angewendet werden soll, oder deaktiviert durch Übergeben einer leeren Instanz: WindowInsets(0, 0, 0, 0)

Um z. B. die Verwendung von eingefügten LargeTopAppBar, Legen Sie den Parameter windowInsets auf eine leere Instanz fest:

LargeTopAppBar(
    windowInsets = WindowInsets(0, 0, 0, 0),
    title = {
        Text("Hi")
    }
)

Interoperabilität mit System-Einbindungen der Ansicht

Möglicherweise müssen Sie die Standardeinfügungen überschreiben, wenn Ihr Bildschirm sowohl Ansichten als auch Erstellen Sie Code in derselben Hierarchie. In diesem Fall müssen Sie explizit welches die Insets aufnehmen und welches sie ignorieren soll.

Wenn das äußerste Layout zum Beispiel ein Android View-Layout ist, sollten Sie die Einsätze im View-System verarbeiten und beim Schreiben ignorieren. Wenn es sich bei Ihrem äußersten Layout um eine zusammensetzbare Funktion handelt, sollten Sie das Element Einfügungen in Compose und füllen Sie die AndroidView zusammensetzbaren Funktionen entsprechend aus.

Standardmäßig verbraucht jeder ComposeView alle Einfügungen an der WindowInsetsCompat Verbrauchslevel. Um dieses Standardverhalten zu ändern, legen Sie Folgendes fest: ComposeView.consumeWindowInsets an false.

Ressourcen