Le modèle de mise en page Compose vous permet d'utiliser la ligne d'alignement (AlignmentLine
) pour créer des lignes d'alignement personnalisées que les mises en page parentes pourront utiliser pour aligner et positionner leurs enfants. Par exemple, Row
(ligne) peut utiliser les lignes d'alignement personnalisées de ses enfants pour les aligner.
Lorsqu'une mise en page fournit une valeur pour uneAlignmentLine
spécifique, les parents de la mise en page peuvent lire cette valeur après la mesure en utilisant l'opérateur Placeable.get
sur l'instance Placeable
correspondante.
En fonction de la position d'AlignmentLine
, les parents peuvent ensuite décider du positionnement des enfants.
Certains composables dans Compose sont déjà dotés de lignes d'alignement. Par exemple, le composable BasicText
expose les lignes d'alignement FirstBaseline
et LastBaseline
.
Dans l'exemple ci-dessous, un modificateur de mise en page (LayoutModifier
) personnalisé nommé firstBaselineToTop
lit la première ligne de base (FirstBaseline
) pour ajouter une marge intérieure au texte (Text
) à partir de sa première ligne de base.
Image 1. Indique la différence entre l'ajout d'une marge intérieure normale à un élément et l'application d'une marge intérieure à la première ligne de base d'un élément textuel.
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) } } @Preview @Composable private fun TextWithPaddingToBaseline() { MaterialTheme { Text("Hi there!", Modifier.firstBaselineToTop(32.dp)) } }
Pour lire la FirstBaseline
dans l'exemple, placeable [FirstBaseline]
est utilisé dans la phase de mesure.
Créer des lignes d'alignement personnalisées
Lorsque vous créez un composable Layout
ou LayoutModifier
personnalisé, vous pouvez fournir des lignes d'alignement personnalisées afin que d'autres composables parents puissent les utiliser pour aligner et positionner leurs enfants.
L'exemple suivant montre un composable BarChart
personnalisé qui expose deux lignes d'alignement, MaxChartValue
et MinChartValue
, afin que d'autres composables puissent s'aligner sur les valeurs maximale et minimale des données du graphique. Deux éléments de texte, Max et Min, ont été alignés au centre des lignes d'alignement personnalisées.
Figure 2. Composable BarChart
avec texte aligné sur les valeurs maximale et minimale des données.
Les lignes d'alignement personnalisées sont définies comme des variables de niveau supérieur dans votre projet.
/** * AlignmentLine defined by the maximum data value in a [BarChart] */ private val MaxChartValue = HorizontalAlignmentLine(merger = { old, new -> min(old, new) }) /** * AlignmentLine defined by the minimum data value in a [BarChart] */ private val MinChartValue = HorizontalAlignmentLine(merger = { old, new -> max(old, new) })
Les lignes d'alignement personnalisées utilisées pour notre exemple sont de type HorizontalAlignmentLine
, car elles permettent d'aligner verticalement les enfants. Une règle de fusion est transmise en tant que paramètre si plusieurs mises en page fournissent une valeur pour ces lignes d'alignement. Puisque les coordonnées du système de mise en page Compose et celle de Canvas
représentent [0, 0]
, le coin supérieur gauche et les axes x
ety
sont des valeurs positives vers le bas de sorte que la valeur MaxChartValue
sera toujours inférieure à celle de MinChartValue
. Par conséquent, la règle de fusion est min
pour la valeur de référence maximale des données de graphique et max
pour la valeur de référence minimale.
Lorsque vous créez une Layout
ou un LayoutModifier
personnalisé, spécifiez des lignes d'alignement personnalisées dans la méthode MeasureScope.layout
, qui accepte un paramètre alignmentLines: Map<AlignmentLine, Int>
.
@Composable private fun BarChart( dataPoints: List<Int>, modifier: Modifier = Modifier, ) { val maxValue: Float = remember(dataPoints) { dataPoints.maxOrNull()!! * 1.2f } BoxWithConstraints(modifier = modifier) { val density = LocalDensity.current with(density) { // ... // Calculate baselines val maxYBaseline = // ... val minYBaseline = // ... Layout( content = {}, modifier = Modifier.drawBehind { // ... } ) { _, constraints -> with(constraints) { layout( width = if (hasBoundedWidth) maxWidth else minWidth, height = if (hasBoundedHeight) maxHeight else minHeight, // Custom AlignmentLines are set here. These are propagated // to direct and indirect parent composables. alignmentLines = mapOf( MinChartValue to minYBaseline.roundToInt(), MaxChartValue to maxYBaseline.roundToInt() ) ) {} } } } } }
Les parents directs et indirects de ce composable peuvent utiliser les lignes d'alignement. Le composable suivant crée une mise en page personnalisée qui utilise comme paramètre deux emplacements Text
et points de données, et aligne les deux textes avec les valeurs maximales et minimales des données de graphique. L'aperçu de ce composable est illustré dans la Figure 2.
@Composable private fun BarChartMinMax( dataPoints: List<Int>, maxText: @Composable () -> Unit, minText: @Composable () -> Unit, modifier: Modifier = Modifier, ) { Layout( content = { maxText() minText() // Set a fixed size to make the example easier to follow BarChart(dataPoints, Modifier.size(200.dp)) }, modifier = modifier ) { measurables, constraints -> check(measurables.size == 3) val placeables = measurables.map { it.measure(constraints.copy(minWidth = 0, minHeight = 0)) } val maxTextPlaceable = placeables[0] val minTextPlaceable = placeables[1] val barChartPlaceable = placeables[2] // Obtain the alignment lines from BarChart to position the Text val minValueBaseline = barChartPlaceable[MinChartValue] val maxValueBaseline = barChartPlaceable[MaxChartValue] layout(constraints.maxWidth, constraints.maxHeight) { maxTextPlaceable.placeRelative( x = 0, y = maxValueBaseline - (maxTextPlaceable.height / 2) ) minTextPlaceable.placeRelative( x = 0, y = minValueBaseline - (minTextPlaceable.height / 2) ) barChartPlaceable.placeRelative( x = max(maxTextPlaceable.width, minTextPlaceable.width) + 20, y = 0 ) } } } @Preview @Composable private fun ChartDataPreview() { MaterialTheme { BarChartMinMax( dataPoints = listOf(4, 24, 15), maxText = { Text("Max") }, minText = { Text("Min") }, modifier = Modifier.padding(24.dp) ) } }
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Éléments graphiques dans Compose
- Mises en page personnalisées {:#custom-layouts }
- Mesures intrinsèques dans les mises en page Compose