Mises en page personnalisées

Dans Compose, les éléments d'interface utilisateur sont représentés par des fonctions modulables qui émettent une partie d'interface utilisateur lorsqu'elles sont appelées, laquelle est alors ajoutée à une arborescence d'interface utilisateur qui s'affiche à l'écran. Chaque élément de l'interface utilisateur a un parent et peut avoir de nombreux enfants. Chaque élément est également situé dans son parent, spécifié sous la forme d'une position (x, y) et d'une taille, indiquée en tant que width et height.

Les parents définissent les contraintes de leurs éléments enfants. Un élément est invité à définir sa taille dans ces contraintes. Ces contraintes limitent les width et height maximales d'un élément. Si un élément comporte des éléments enfants, il peut mesurer chaque enfant pour déterminer sa taille. Une fois qu'un élément détermine et indique sa propre taille, il peut définir comment positionner ses éléments enfants par rapport à lui-même, comme décrit en détail dans Créer des mises en page personnalisées.

La mise en page de chaque nœud dans l'arborescence de l'interface utilisateur s'effectue en trois étapes. Chaque nœud doit :

  1. Mesurer tout élément enfant
  2. Déterminer sa propre taille
  3. Placer ses éléments enfants

La mise en page des nœuds en trois étapes : mesurer les enfants, choisir la taille, placer les enfants

L'utilisation des champs d'application définit quand mesurer et placer vos enfants. Vous ne pouvez mesurer une mise en page que lors des passes de mesure et de mise en page. De plus, un enfant ne peut être placé que pendant les passes de mise en page (et seulement après avoir été mesuré). En raison des champs d'application Compose tels que MeasureScope et PlacementScope, cette opération est appliquée au moment de la compilation.

Utiliser le modificateur de mise en page

Vous pouvez utiliser le modificateur layout pour changer la façon dont un élément est mesuré et mis en page. Layout est un lambda. Ses paramètres incluent l'élément que vous pouvez mesurer, transmis en tant que measurable, ainsi que les contraintes entrantes de ce composable, transmises en tant que constraints. Un modificateur de mise en page personnalisé peut se présenter comme ceci :

fun Modifier.customLayoutModifier() =
    layout { measurable, constraints ->
        // ...
    }

Affichons un Text à l'écran et contrôlons la distance entre le haut et la ligne de la première ligne de texte. C'est exactement ce que fait le modificateur paddingFromBaseline, que nous intégrons ici à titre d'exemple. Pour ce faire, utilisez le modificateur layout pour placer manuellement le composable sur l'écran. Voici le comportement souhaité lorsque la marge intérieure supérieure de Text est définie sur 24.dp :

Affiche la différence entre une marge intérieure d'interface utilisateur normale, qui définit l'espace entre les éléments, et une marge intérieure de texte qui définit l'espace d'une ligne à l'autre.

Voici le code permettant de créer cet espacement :

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

Voici ce qui se passe dans ce code :

  1. Dans le paramètre lambda measurable, vous mesurez le Text représenté par le paramètre mesurable en appelant measurable.measure(constraints).
  2. Vous précisez la taille du composable en appelant la méthode layout(width, height), qui fournit également un lambda utilisé pour placer les éléments encapsulés. Dans ce cas, il s'agit de la hauteur entre la dernière référence et la marge intérieure supérieure ajoutée.
  3. Vous pouvez positionner les éléments encapsulés sur l'écran en appelant placeable.place(x, y). Si les éléments encapsulés ne sont pas placés, ils ne seront pas visibles. La position y correspond à la marge supérieure, c'est-à-dire à la première ligne du texte.

Pour vérifier que tout fonctionne comme prévu, utilisez ce modificateur sur un 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))
    }
}

Différents aperçus d'éléments textuels : l'un montre une marge intérieure normale entre des éléments, l'autre une marge intérieure d'une ligne à l'autre

Créer des mises en page personnalisées

Le modificateur layout ne modifie que le composable appelant. Pour mesurer et mettre en page plusieurs composables, utilisez plutôt le composable Layout. Ce composable vous permet de mesurer et de positionner manuellement les enfants. Toutes les mises en page de niveau supérieur, comme Column et Row, sont créées avec le composable Layout.

Créons une version très basique de Column. La plupart des mises en page personnalisées suivent le modèle suivant :

@Composable
fun MyBasicColumn(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->
        // measure and position children given constraints logic here
        // ...
    }
}

Comme pour le modificateur layout, measurables est la liste des enfants à mesurer et constraints les contraintes du parent. En suivant la même logique qu'auparavant, MyBasicColumn peut être intégré comme suit :

@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
            }
        }
    }
}

Les composables enfants sont limités par les contraintes Layout (sans les contraintes minHeight) et ils sont placés selon la yPosition du composable précédent.

Voici comment ce composable personnalisé serait utilisé :

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

Plusieurs éléments de texte empilés les uns au-dessus des autres dans une colonne.

Orientation de la mise en page

Modifiez l'orientation de la mise en page d'un composable en modifiant la composition LocalLayoutDirection en local.

Si vous positionnez des composables manuellement sur l'écran, LayoutDirection fait partie du LayoutScope du modificateur layout ou du composable Layout.

Lorsque vous utilisez layoutDirection, placez des composables à l'aide de place. Contrairement à la méthode placeRelative, place ne change pas en fonction de l'orientation de la mise en page (de gauche à droite ou de droite à gauche).

Mises en page personnalisées à l'œuvre

Pour en savoir plus sur les mises en page et les modificateurs, consultez la page Mises en page de base dans Compose. Pour découvrir comment utiliser les mises en page personnalisées, consultez les exemples de création de mises en page personnalisées dans Compose.

En savoir plus

Pour en savoir plus sur les mises en page personnalisées dans Compose, consultez les ressources supplémentaires suivantes.

Vidéos