L'une des règles de Compose est de ne mesurer vos éléments enfants qu'une seule fois. Si vous les mesurez deux fois, une exception d'exécution est générée. Toutefois, il arrive que vous ayez besoin d'informations sur vos éléments enfants avant de les mesurer.
Les fonctionnalités intrinsèques vous permettent d'interroger des éléments enfants avant qu'ils ne soient réellement mesurés.
Dans le cas d'un composable, vous pouvez demander son IntrinsicSize.Min
ou IntrinsicSize.Max
:
Modifier.width(IntrinsicSize.Min)
: quelle est la largeur minimale dont vous avez besoin pour afficher correctement votre contenu ?Modifier.width(IntrinsicSize.Max)
: quelle est la largeur maximale dont vous avez besoin pour afficher correctement votre contenu ?Modifier.height(IntrinsicSize.Min)
: quelle est la hauteur minimale requise pour afficher correctement votre contenu ?Modifier.height(IntrinsicSize.Max)
: quelle est la hauteur maximale dont vous avez besoin pour afficher correctement votre contenu ?
Par exemple, si vous demandez la minIntrinsicHeight
d'un Text
avec des contraintes width
infinies dans une mise en page personnalisée, la height
du Text
est renvoyée avec le texte dessiné sur une seule ligne.
Fonctionnalités intrinsèques en action
Vous pouvez créer un composable qui affiche à l'écran deux éléments textuels séparés par un séparateur :
Pour ce faire, utilisez un Row
avec deux composables Text
qui remplissent l'espace disponible et un Divider
au milieu. Divider
doit être aussi grand que l'élément Text
le plus grand et doit être fin (width = 1.dp
).
@Composable fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) { Row(modifier = modifier) { Text( modifier = Modifier .weight(1f) .padding(start = 4.dp) .wrapContentWidth(Alignment.Start), text = text1 ) VerticalDivider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } }
Le Divider
s'étend sur tout l'écran, ce qui n'est pas le comportement souhaité :
Cela est dû au fait que Row
mesure chaque élément enfant séparément et que la hauteur de Text
ne peut pas être utilisée pour limiter le Divider
.
Pour que Divider
remplisse l'espace disponible avec une hauteur donnée, utilisez le modificateur height(IntrinsicSize.Min)
.
height(IntrinsicSize.Min)
dimensionne ses éléments enfants en les forçant à être aussi grands que leur hauteur intrinsèque minimale. Comme ce modificateur est récursif, il interroge le minIntrinsicHeight
du Row
et de ses enfants.
Si vous appliquez ce modificateur à votre code, il fonctionnera comme prévu :
@Composable fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) { Row(modifier = modifier.height(IntrinsicSize.Min)) { Text( modifier = Modifier .weight(1f) .padding(start = 4.dp) .wrapContentWidth(Alignment.Start), text = text1 ) VerticalDivider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } } // @Preview @Composable fun TwoTextsPreview() { MaterialTheme { Surface { TwoTexts(text1 = "Hi", text2 = "there") } } }
Avec l'aperçu :
La hauteur de Row
est déterminée comme suit :
- La propriété
minIntrinsicHeight
du composableRow
correspond à la valeurminIntrinsicHeight
maximale de ses éléments enfants. - La propriété
minIntrinsicHeight
de l'élémentDivider
est 0, car elle n'occupe pas d'espace si aucune contrainte n'est spécifiée. - Le
minIntrinsicHeight
Text
est celui du texte pour unwidth
spécifique. - Par conséquent, la contrainte
height
de l'élémentRow
devient la valeurminIntrinsicHeight
maximale des élémentsText
. - Le
Divider
étend ensuite sonheight
à la contrainteheight
fournie parRow
.
Fonctionnalités intrinsèques dans vos mises en page personnalisées
Lorsque vous créez un modificateur Layout
ou layout
personnalisé, les mesures intrinsèques sont calculées automatiquement en fonction d'approximations. Par conséquent, les calculs ne seront peut-être pas corrects pour toutes les mises en page. Ces API offrent des options pour remplacer ces valeurs par défaut.
Pour spécifier les mesures intrinsèques de votre Layout
personnalisée, remplacez les valeurs minIntrinsicWidth
, minIntrinsicHeight
, maxIntrinsicWidth
et maxIntrinsicHeight
de l'interface MeasurePolicy
lors de sa création.
@Composable fun MyCustomComposable( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( content = content, modifier = modifier, measurePolicy = object : MeasurePolicy { override fun MeasureScope.measure( measurables: List<Measurable>, constraints: Constraints ): MeasureResult { // Measure and layout here // ... } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurables: List<IntrinsicMeasurable>, height: Int ): Int { // Logic here // ... } // Other intrinsics related methods have a default value, // you can override only the methods that you need. } ) }
Lorsque vous créez votre modificateur layout
personnalisé, remplacez les méthodes associées dans l'interface LayoutModifier
.
fun Modifier.myCustomModifier(/* ... */) = this then object : LayoutModifier { override fun MeasureScope.measure( measurable: Measurable, constraints: Constraints ): MeasureResult { // Measure and layout here // ... } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurable: IntrinsicMeasurable, height: Int ): Int { // Logic here // ... } // Other intrinsics related methods have a default value, // you can override only the methods that you need. }
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Mises en page personnalisées {:#custom-layouts}
- Lignes d'alignement dans Jetpack Compose
- Phases de Jetpack Compose