WindowInsets
ist die Standard-API in Jetpack Compose zum Verarbeiten von Bereichen des Bildschirms, die teilweise oder vollständig von der System-UI verdeckt werden. Dazu gehören die Statusleiste, die Navigationsleiste und die Bildschirmtastatur. Alternativ können Sie vordefinierte WindowInsetsRulers
wie SafeDrawing
an Modifier.fitInside
oder Modifier.fitOutside
übergeben, um Ihre Inhalte an die Systemleisten und den Displayausschnitt anzupassen oder benutzerdefinierte WindowInsetsRulers
zu erstellen.
Vorteile von WindowInsetsRulers
- Vermeidung von Komplexität bei der Nutzung: Die Funktion wird während der Platzierungsphase des Layouts ausgeführt. Das bedeutet, dass die Inset-Kette vollständig umgangen wird und immer die korrekten, absoluten Positionen von Systemleisten und Displayausschnitten bereitgestellt werden können, unabhängig davon, was in übergeordneten Layouts passiert ist. Die Methoden
Modifier.fitInside
oderModifier.fitOutside
können hilfreich sein, um Probleme zu beheben, wenn übergeordnete Composables Insets falsch verwenden. - Systemleisten einfach vermeiden: Mit dieser Funktion können Sie dafür sorgen, dass die Inhalte Ihrer App nicht von Systemleisten und dem Displayausschnitt verdeckt werden. Das ist möglicherweise einfacher als die direkte Verwendung von
WindowInsets
. - Hohe Anpassbarkeit: Entwickler können Inhalte an benutzerdefinierten Linealen ausrichten und mit benutzerdefinierten Layouts präzise Kontrolle über ihre Layouts haben.
Nachteile von WindowInsetsRulers
- Kann nicht für die Analyse verwendet werden: Da die Funktion während der Platzierungsphase ausgeführt wird, sind die Positionsinformationen, die sie liefert, während der früheren Analysephase nicht verfügbar.
- Mögliche Layoutinstabilität: Dies kann zu Abstürzen führen, wenn die Größe eines übergeordneten Layouts von der Größe seiner untergeordneten Elemente abhängt. Da ein untergeordnetes Element, das
WindowInsetsRulers
verwendet, seine Position oder Größe während der Platzierung ändern kann, kann dies zu einem instabilen Layoutzyklus führen.
Benutzerdefinierte WindowInsetsRulers
erstellen
Sie können Inhalte an benutzerdefinierten Linealen ausrichten. Stellen Sie sich beispielsweise den Anwendungsfall vor, in dem ein übergeordnetes Composable Insets nicht richtig verarbeitet, was zu Padding-Problemen in einem untergeordneten Element führt. Dieses Problem kann auch auf andere Weise behoben werden, z. B. durch die Verwendung von Modifier.fitInside
. Sie können aber auch ein benutzerdefiniertes Lineal erstellen, um das untergeordnete Composable-Element präzise auszurichten, ohne das Problem im übergeordneten Element zu beheben. Das folgende Beispiel und Video zeigen, wie das geht:
@Composable fun WindowInsetsRulersDemo(modifier: Modifier) { Box( contentAlignment = BottomCenter, modifier = modifier .fillMaxSize() // The mistake that causes issues downstream, as .padding doesn't consume insets. // While it's correct to instead use .windowInsetsPadding(WindowInsets.navigationBars), // assume it's difficult to identify this issue to see how WindowInsetsRulers can help. .padding(WindowInsets.navigationBars.asPaddingValues()) ) { TextField( value = "Demo IME Insets", onValueChange = {}, modifier = modifier // Use alignToSafeDrawing() instead of .imePadding() to precisely place this child // Composable without having to fix the parent upstream. .alignToSafeDrawing() // .imePadding() // .fillMaxWidth() ) } } fun Modifier.alignToSafeDrawing(): Modifier { return layout { measurable, constraints -> if (constraints.hasBoundedWidth && constraints.hasBoundedHeight) { val placeable = measurable.measure(constraints) val width = placeable.width val height = placeable.height layout(width, height) { val bottom = WindowInsetsRulers.SafeDrawing.current.bottom .current(0f).roundToInt() - height val right = WindowInsetsRulers.SafeDrawing.current.right .current(0f).roundToInt() val left = WindowInsetsRulers.SafeDrawing.current.left .current(0f).roundToInt() measurable.measure(Constraints.fixed(right - left, height)) .place(left, bottom) } } else { val placeable = measurable.measure(constraints) layout(placeable.width, placeable.height) { placeable.place(0, 0) } } } }
Im folgenden Video sehen Sie ein Beispiel für die problematische Verwendung von IME-Insets, die durch ein übergeordnetes Element im Bild links verursacht wird. Rechts sehen Sie, wie das Problem mit benutzerdefinierten Linealen behoben wird. Unter dem TextField
-Composable wird zusätzlicher Abstand angezeigt, da der Abstand der Navigationsleiste nicht vom übergeordneten Element verwendet wurde. Das Kind wird mit einem benutzerdefinierten Lineal an der richtigen Stelle im richtigen Bild platziert, wie im vorherigen Codebeispiel zu sehen ist.
Prüfen, ob Eltern eingeschränkt sind
Damit WindowInsetsRulers
sicher verwendet werden kann, müssen die Eltern gültige Einschränkungen festlegen. Übergeordnete Elemente müssen eine definierte Größe haben und dürfen nicht von der Größe eines untergeordneten Elements abhängen, für das WindowInsetsRulers
verwendet wird. Verwenden Sie fillMaxSize
oder andere Größenmodifikatoren für übergeordnete Composables.
Wenn Sie eine Komponente, die WindowInsetsRulers
verwendet, in einen Scrolling-Container wie verticalScroll
einfügen, kann dies ebenfalls zu unerwartetem Verhalten führen, da der Scrolling-Container unbegrenzte Höhenbeschränkungen bietet, die mit der Logik des Lineals nicht kompatibel sind.