Jetpack Compose-Layouts / Sudo Null IT-News

Manchmal reichen Row, Column, Box und andere eingebaute Container für das Layout komplexer Bildschirme nicht aus, dann müssen wir unsere eigenen schreiben. In diesem Artikel schreiben wir eine Zeile, die untergeordnete Elemente in die nächste Zeile umbricht, wenn nicht genügend Platz vorhanden ist.

Dieser Artikel ist in 2 Teile gegliedert: Grundlagen und Fortgeschrittene.

Compose verwendet das Layout-Element, um benutzerdefinierte Container zu erstellen:

@Composable fun Layout (Inhalt: @Composable () -> Einheit, Modifikator: Modifikator = Modifikator, Maßrichtlinie: Maßeinheit)

  • Inhalt – der Körper des Containers, der alle untergeordneten Elemente enthält.

  • measurePolicy – ​​ein Objekt, das für die Anordnung von Elementen innerhalb des Containers verantwortlich ist

Das Hauptelement sieht folgendermaßen aus:

@Composable Inline Fun RowWithWrap( Modifier: Modifier = Modifier, verticalSpacer: Dp = 0.dp, horizontalSpacer: Dp = 0.dp, content: @Composable () -> Unit ) { Box(modifier) ​​​​{ Layout( content = content, measurePolicy = rowWithWrapMesaurePolicy(verticalSpacer, horizontalSpacer) ) } }

  • verticalSpacer und horizontalSpacer – vertikaler bzw. horizontaler Abstand zwischen Elementen.

  • Box(modifier) ​​​​ist eine kleine Krücke. Wir können Layout nicht dazu zwingen, Modifikator auf Basisartikelebene korrekt zu verarbeiten. Wir werden dies in einem erweiterten Artikel lösen.

  • rowWithWrapMesaurePolicy erstellt eine Richtlinie zum Positionieren von Elementen basierend auf Padding. Dies wird auch im erweiterten Artikel benötigt.

@Composable fun rowWithWrapMesaurePolicy(vertikalSpacer: Dp = 0.dp, horizontalSpacer: Dp = 0.dp): MeasurePolicy = Remember(verticalSpacer, horizontalSpacer) { MeasurePolicy {messbar: List, Constraints: Constraints -> val positions = rowWithWrapRelativePositions( Constraints, measurables, verticalSpacer, horizontalSpacer) val width = maxOf(positions.maxOf { it.maxXCoordinate }, Constraints.minWidth) val height = minOf(maxOf(positions.maxOf { it.maxYCoordinate }, Constraints.minHeight), Constraints.maxHeight ) layout(width, height) { for ((placeable, dx, dy) in positions) { placeable.placeRelative(dx, dy) } } } }

  • Wir müssen Remember verwenden, um nicht bei jeder Neuzusammensetzung zusätzliche Objekte zu erstellen.

  • MeasurePolicy ist eine Schnittstelle, bei der eine nicht implementiert ist, sodass wir einen Lambda-Ausdruck verwenden können.

  • messbar – alle untergeordneten Elemente des Containers.

  • Einschränkungen – Größenbeschränkungen

  • Die Methode rowWithWrapRelativePositions berechnet die Position aller Elemente relativ zur oberen linken Ecke des Containers. Gibt unsere Datenklasse zurück, aber dazu später mehr.

  • layout(width, height) legt die Größe des Containers fest. Darin platzieren wir alle Elemente an den zuvor berechneten Stellen.

privater Spaß MeasureScope.rowWithWrapRelativePositions( Constraints: Constraints, measurables: List, verticalSpacer: Dp, horizontalSpacer: Dp ): List { val res = mutableListOf() var x = 0 var y = 0 var maxHeight = -1 for (messbar in messbar) { val placeable = messbar.measure(constraints) if (placeable.width + x > constraints.maxWidth) { y += maxHeight + verticalSpacer.roundToPx() x = 0 maxHeight = -1 } res += PlaceableRelativePosition(placeable, x, y) x += placeable.width + horizontalSpacer.roundToPx() maxHeight = maxOf(maxHeight, placeable.height) } return res } private data class PlaceableRelativePosition(val placeable: Placeable, val dx: Int, val dy: Int) private val PlaceableRelativePosition.maxXCoordinate: Int get() = dx + placeable.width private val PlaceableRelativePosition.maxYCoordinate: Int get() = dy + placeable.height

  • Measurable::measure berechnet die Abmessungen des untergeordneten Elements basierend auf den äußeren Einschränkungen.

  • maxXCoordinate und maxYCoordinate sind die ganz rechts bzw. ganz unten belegten Plätze.

Ergebnis:

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *