Jedną z reguł usługi Compose jest to, że elementy potomne należy mierzyć tylko raz. Podwójne zliczanie elementów potomnych powoduje wyjątek czasu wykonywania. Czasami jednak przed pomiarem potrzebujesz pewnych informacji o swoich dzieciach.
Za pomocą funkcji Intrinsics możesz wysyłać zapytania dotyczące elementów składowych, zanim zostaną one zmierzone.
W komponowalnym możesz poprosić o intrinsicWidth
lub intrinsicHeight
:
(min|max)IntrinsicWidth
: Jaka jest minimalna/maksymalna szerokość, przy której treści są wyświetlane prawidłowo?(min|max)IntrinsicHeight
: Jaka jest minimalna/maksymalna wysokość, przy której można prawidłowo namalować treści?
Jeśli na przykład poprosisz o minIntrinsicHeight
w przypadku Text
z nieskończoną liczbą wierszy height
, zwróci on height
w przypadku Text
tak, jakby tekst był zapisany w jednym wierszu.
Elementy wbudowane w praktykę
Załóżmy, że chcemy utworzyć funkcję kompozycyjną, w której na ekranie wyświetlają się 2 teksty rozdzielone separatorami w ten sposób:
Jak to zrobić? Możemy mieć Row
z 2 Text
wewnątrz, które rozszerza się tak bardzo, jak to możliwe, oraz Divider
w środku. Divider
musi mieć wysokość
najwyższego elementu (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 ) HorizontalDivider( 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
zajmuje cały ekran, a nie chcemy tego:
Dzieje się tak, ponieważ funkcja Row
mierzy każdy element podrzędny osobno, a wysokość elementu Text
nie może być używana do ograniczania elementu Divider
. Chcemy, aby element Divider
wypełniał dostępną przestrzeń o określonej wysokości. Można do tego użyć modyfikatora height(IntrinsicSize.Min)
.
height(IntrinsicSize.Min)
określa rozmiary swoich elementów, które muszą mieć wysokość odpowiadającą ich minimalnej wysokości. Jest to zapytanie rekurencyjne, które przeszuka Row
i jego podelementy minIntrinsicHeight
.
Po zastosowaniu tego 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 ) HorizontalDivider( 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
kompozytowa będzie równa maksymalnej wartości minIntrinsicHeight
jego elementów.minIntrinsicHeight
Wartość minIntrinsicHeight
elementu Divider
ma wartość 0, ponieważ nie zajmuje miejsca bez żadnych ograniczeń. Text
minIntrinsicHeight
to tekst tekstu o określonej wartości width
. Dlatego ograniczenie height
elementu Row
będzie maksymalną wartością minIntrinsicHeight
elementu Text
. Divider
rozszerzy wtedy swoje height
na ograniczenie height
podane przez Row
.
Elementy niestandardowe w układach niestandardowych
Podczas tworzenia niestandardowego modyfikatora Layout
lub layout
pomiary wewnętrzne są obliczane automatycznie na podstawie przybliżeń. Z tego powodu obliczenia mogą nie być prawidłowe w przypadku niektórych układów. Te interfejsy API oferują opcje umożliwiające zastąpienie tych ustawień domyślnych.
Aby określić wewnętrzne pomiary niestandardowego Layout
, podczas tworzenia go zastąp minIntrinsicWidth
, minIntrinsicHeight
, maxIntrinsicWidth
i maxIntrinsicHeight
interfejsu MeasurePolicy
.
@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ąpij 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 obsługa JavaScript jest wyłączona
- Układy niestandardowe {:#custom-layouts }
- Linia wyrównania w Jetpack Compose
- Etapy Jetpack Compose