Jedna z zasad Compose mówi, że dzieci należy mierzyć tylko raz. Dwukrotne zmierzenie dzieci powoduje wyjątek w czasie działania. Czasami jednak przed pomiarem musisz uzyskać pewne informacje o dzieciach.
Intrinsics umożliwia wysyłanie zapytań dotyczących dzieci, zanim zostaną one zmierzone.
W przypadku funkcji kompozycyjnej możesz poprosić o jej IntrinsicSize.Min
lub IntrinsicSize.Max
:
Modifier.width(IntrinsicSize.Min)
– jaka jest minimalna szerokość, która jest potrzebna do prawidłowego wyświetlania treści?Modifier.width(IntrinsicSize.Max)
– Jaka jest maksymalna szerokość, której potrzebujesz, aby prawidłowo wyświetlać treści?Modifier.height(IntrinsicSize.Min)
– Jaka jest minimalna wysokość potrzebna do prawidłowego wyświetlania treści?Modifier.height(IntrinsicSize.Max)
– Jaka jest maksymalna wysokość, której potrzebujesz, aby prawidłowo wyświetlać treści?
Jeśli na przykład zapytasz o minIntrinsicHeight
Text
z nieskończonymiwidth
ograniczeniami w układzie niestandardowym, zwróci height
Text
z tekstem narysowanym w jednym wierszu.
Funkcje pierwotne w praktyce
Załóżmy, że chcemy utworzyć komponent, który wyświetla na ekranie 2 teksty oddzielone separatorem, tak jak poniżej:
Jak możemy to zrobić? Możemy mieć Row
z 2 Text
w środku, który rozszerza się tak bardzo, jak to możliwe, oraz Divider
pośrodku. Chcemy, aby Divider
był tak wysoki jak najwyższy Text
i cienki (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 ) } }
Jeśli wyświetlimy podgląd, zobaczymy, że Divider
rozszerza się na cały ekran, a tego nie chcemy:
Dzieje się tak, ponieważ Row
mierzy każde dziecko osobno, a wysokość Text
nie może być używana do ograniczenia Divider
. Chcemy, aby element Divider
wypełniał dostępną przestrzeń o określonej wysokości. Możemy do tego użyć modyfikatora height(IntrinsicSize.Min)
.
height(IntrinsicSize.Min)
wymusza na elementach podrzędnych wysokość równą ich minimalnej wysokości wewnętrznej. Ponieważ jest to zapytanie rekurencyjne, wyszuka ono Row
i jego elementy podrzędne minIntrinsicHeight
.
Jeśli zastosujemy to w naszym kodzie, będzie on działać zgodnie z oczekiwaniami:
@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") } } }
Z podglądem:
Wartość Row
elementu kompozycyjnego minIntrinsicHeight
będzie maksymalną wartością minIntrinsicHeight
jego elementów podrzędnych. Wartość Divider
elementu minIntrinsicHeight
wynosi 0, ponieważ nie zajmuje on miejsca, jeśli nie podano żadnych ograniczeń. Wartość Text
minIntrinsicHeight
będzie wartością tekstu przy danym width
. Dlatego ograniczenie height
elementu Row
będzie maksymalną wartością minIntrinsicHeight
z wartości Text
. Divider
rozszerzy wtedy swój height
do height
ograniczenia podanego przez Row
.
Wartości wewnętrzne w układach niestandardowych
Podczas tworzenia niestandardowego modyfikatora Layout
lub layout
pomiary wewnętrzne są obliczane automatycznie na podstawie przybliżeń. Dlatego obliczenia mogą nie być prawidłowe w przypadku wszystkich układów. Te interfejsy API oferują opcje zastępowania tych ustawień domyślnych.
Aby określić pomiary wewnętrzne niestandardowego Layout
, zastąp wartości minIntrinsicWidth
, minIntrinsicHeight
, maxIntrinsicWidth
i maxIntrinsicHeight
interfejsu MeasurePolicy
podczas jego tworzenia.
@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. } ) }
Podczas tworzenia niestandardowego modyfikatora layout
zastąp powiązane metody w interfejsie 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. }
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy JavaScript jest wyłączony.
- Układy niestandardowe {:#custom-layouts }
- Linie wyrównania w Jetpack Compose
- Etapy Jetpack Compose