In Compose werden UI-Elemente durch zusammensetzbare Funktionen dargestellt, die beim Aufruf einen Teil der UI ausgeben. Dieser wird dann einem UI-Baum hinzugefügt, der auf dem Bildschirm gerendert wird. Jedes UI-Element hat ein übergeordnetes Element und potenziell viele untergeordnete Elemente. Jedes Element befindet sich außerdem innerhalb seines übergeordneten Elements, angegeben als (x, y)-Position, und hat eine Größe, angegeben als width und height.
Übergeordnete Elemente definieren die Einschränkungen für ihre untergeordneten Elemente. Ein Element wird aufgefordert, seine Größe innerhalb dieser Einschränkungen zu definieren. Einschränkungen begrenzen die minimale und maximale width und height eines Elements. Wenn ein Element untergeordnete Elemente hat, kann es jedes untergeordnete Element messen, um seine Größe zu bestimmen. Nachdem ein Element seine eigene Größe bestimmt und gemeldet hat, kann es definieren, wie seine untergeordneten Elemente relativ zu ihm platziert werden sollen. Dies wird im Abschnitt Benutzerdefinierte Layouts erstellen ausführlich beschrieben.
Das Layout der einzelnen Knoten im UI-Baum ist ein dreistufiger Prozess. Jeder Knoten muss:
- Kinder messen
- Größe selbst festlegen
- Untergeordnete Elemente platzieren
Durch die Verwendung von Bereichen wird definiert, wann Sie Ihre untergeordneten Elemente messen und platzieren können.
Das Messen eines Layouts ist nur während der Mess- und Layoutdurchgänge möglich. Ein untergeordnetes Element kann nur während der Layoutdurchgänge platziert werden (und erst, nachdem es gemessen wurde). Aufgrund von Compose-Bereichen wie MeasureScope und PlacementScope wird dies zur Kompilierungszeit erzwungen.
Layoutmodifikator verwenden
Mit dem Modifikator layout können Sie ändern, wie ein Element gemessen und angeordnet wird. Layout ist ein Lambda-Ausdruck. Zu den Parametern gehören das Element, das Sie messen können, übergeben als measurable, und die eingehenden Einschränkungen dieser zusammensetzbaren Funktion, übergeben als constraints. Ein benutzerdefinierter Layoutmodifikator kann so aussehen:
fun Modifier.customLayoutModifier() = layout { measurable, constraints -> // ... }
Zeigt ein Text auf dem Bildschirm an und steuert den Abstand vom oberen Rand zur Grundlinie der ersten Textzeile. Genau das macht der Modifikator paddingFromBaseline. Sie implementieren ihn hier als Beispiel.
Verwende dazu den Modifikator layout, um die komponierbare Funktion manuell auf dem Bildschirm zu platzieren. Hier ist das resultierende Verhalten, wenn das obere Padding von Text auf 24.dp gesetzt ist:
paddingFromBaseline.
Hier ist der Code, um diesen Abstand zu erzeugen:
fun Modifier.firstBaselineToTop( firstBaselineToTop: Dp ) = layout { measurable, constraints -> // Measure the composable val placeable = measurable.measure(constraints) // Check the composable has a first baseline check(placeable[FirstBaseline] != AlignmentLine.Unspecified) val firstBaseline = placeable[FirstBaseline] // Height of the composable with padding - first baseline val placeableY = firstBaselineToTop.roundToPx() - firstBaseline val height = placeable.height + placeableY layout(placeable.width, height) { // Where the composable gets placed placeable.placeRelative(0, placeableY) } }
Das passiert in diesem Code:
- Im Lambda-Parameter
measurablemessen Sie denText, der durch den messbaren Parameter dargestellt wird, indem Siemeasurable.measure(constraints)aufrufen. - Sie geben die Größe der komponierbaren Funktion an, indem Sie die Methode
layout(width, height)aufrufen. Dadurch wird auch ein Lambda-Ausdruck bereitgestellt, mit dem die umschlossenen Elemente platziert werden. In diesem Fall ist es die Höhe zwischen der letzten Grundlinie und dem hinzugefügten oberen Abstand. - Sie positionieren die umschlossenen Elemente auf dem Bildschirm, indem Sie
placeable.place(x, y)aufrufen. Wenn die umschlossenen Elemente nicht platziert werden, sind sie nicht sichtbar. Die Positionyentspricht dem oberen Abstand: der Position der ersten Grundlinie des Texts.
Wenn Sie prüfen möchten, ob dies wie erwartet funktioniert, verwenden Sie diesen Modifikator für ein Text:
@Preview @Composable fun TextWithPaddingToBaselinePreview() { MyApplicationTheme { Text("Hi there!", Modifier.firstBaselineToTop(32.dp)) } } @Preview @Composable fun TextWithNormalPaddingPreview() { MyApplicationTheme { Text("Hi there!", Modifier.padding(top = 32.dp)) } }
Text-Composable angewendeter und in der Vorschau angezeigter Modifikator.
Benutzerdefinierte Layouts erstellen
Der Modifikator layout ändert nur die aufrufende Komposition. Wenn Sie mehrere Composables messen und anordnen möchten, verwenden Sie stattdessen das Composable Layout. Mit dieser zusammensetzbaren Funktion können Sie untergeordnete Elemente manuell messen und anordnen. Alle übergeordneten Layouts wie Column und Row werden mit der zusammensetzbaren Funktion Layout erstellt.
In diesem Beispiel wird eine sehr einfache Version von Column erstellt. Die meisten benutzerdefinierten Layouts folgen diesem Muster:
@Composable fun MyBasicColumn( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( modifier = modifier, content = content ) { measurables, constraints -> // measure and position children given constraints logic here // ... } }
Ähnlich wie beim Modifikator layout ist measurables die Liste der untergeordneten Elemente, die gemessen werden müssen, und constraints sind die Einschränkungen des übergeordneten Elements.
Nach derselben Logik wie zuvor kann MyBasicColumn so implementiert werden:
@Composable fun MyBasicColumn( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( modifier = modifier, content = content ) { measurables, constraints -> // Don't constrain child views further, measure them with given constraints // List of measured children val placeables = measurables.map { measurable -> // Measure each children measurable.measure(constraints) } // Set the size of the layout as big as it can layout(constraints.maxWidth, constraints.maxHeight) { // Track the y co-ord we have placed children up to var yPosition = 0 // Place children in the parent layout placeables.forEach { placeable -> // Position item on the screen placeable.placeRelative(x = 0, y = yPosition) // Record the y co-ord placed up to yPosition += placeable.height } } } }
Die untergeordneten Composables sind durch die Layout-Einschränkungen (ohne die minHeight-Einschränkungen) eingeschränkt und werden basierend auf dem yPosition des vorherigen Composables platziert.
So wird diese benutzerdefinierte Komposition verwendet:
@Composable fun CallingComposable(modifier: Modifier = Modifier) { MyBasicColumn(modifier.padding(8.dp)) { Text("MyBasicColumn") Text("places items") Text("vertically.") Text("We've done it by hand!") } }
Column-Implementierung.
Layoutrichtung
Sie können die Layoutrichtung einer zusammensetzbaren Funktion ändern, indem Sie die lokale Zusammensetzung LocalLayoutDirection ändern.
Wenn Sie zusammensetzbare Funktionen manuell auf dem Bildschirm platzieren, ist die LayoutDirection Teil der LayoutScope des Modifikators layout oder der zusammensetzbaren Funktion Layout.
Wenn Sie layoutDirection verwenden, platzieren Sie Composables mit place. Im Gegensatz zur Methode placeRelative ändert sich place nicht je nach Layoutrichtung (von links nach rechts oder von rechts nach links).
Benutzerdefinierte Layouts in der Praxis
Weitere Informationen zu Layouts und Modifikatoren findest du unter Grundlegende Layouts in Compose. Benutzerdefinierte Layouts in Aktion findest du in den Compose-Beispielen, die benutzerdefinierte Layouts erstellen.
Weitere Informationen
Weitere Informationen zu benutzerdefinierten Layouts in Compose finden Sie in den folgenden zusätzlichen Ressourcen.
Videos
Empfehlungen für Sie
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Intrinsische Messungen in Compose-Layouts
- Grafiken in Compose
- Compose-Modifikatoren