Одно из правил Compose заключается в том, что дочерние элементы следует измерять только один раз; измерение дочерних элементов дважды приводит к исключению во время выполнения. Однако бывают случаи, когда вам необходима некоторая информация о дочерних элементах, прежде чем измерять их.
Функция Intrinsics позволяет запрашивать данные у дочерних элементов до того, как они будут фактически измерены.
К компонуемому объекту можно запросить его IntrinsicSize.Min или IntrinsicSize.Max :
-
Modifier.width(IntrinsicSize.Min)- Какова минимальная ширина, необходимая для корректного отображения контента? -
Modifier.width(IntrinsicSize.Max)- Какова максимальная ширина, необходимая для корректного отображения контента? -
Modifier.height(IntrinsicSize.Min)- Какова минимальная высота, необходимая для корректного отображения контента? -
Modifier.height(IntrinsicSize.Max)- Какова максимальная высота, необходимая для корректного отображения контента?
Например, если вы запрашиваете значение minIntrinsicHeight для Text с бесконечной width в пользовательском макете, система вернет height Text , отображаемого в одну строку.
Внутренние механизмы в действии
Вы можете создать составной элемент, который отображает на экране два текста, разделенных разделителем:

Для этого используйте Row с двумя составными Text элементами, заполняющими доступное пространство, и Divider посередине. Divider должен быть такой же высоты, как и самый высокий Text , и должен быть узким ( 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 ) } }
Divider разворачивается на весь экран, что нежелательно:

Это происходит потому, что Row измеряет каждый дочерний элемент индивидуально, и высоту Text нельзя использовать для ограничения Divider .
Чтобы Divider заполнял доступное пространство заданной высотой, используйте модификатор height(IntrinsicSize.Min) .
height(IntrinsicSize.Min) ` задает высоту дочерних элементов таким образом, чтобы она соответствовала их минимальной внутренней высоте. Поскольку этот модификатор является рекурсивным, он запрашивает значение minIntrinsicHeight для Row и ее дочерних элементов.
Применение этого модификатора к вашему коду обеспечивает его корректную работу:
@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") } } }
С предварительным просмотром:

Высота Row определяется следующим образом:
-
minIntrinsicHeightобъектаRowcomposable равен максимальномуminIntrinsicHeightего дочерних элементов. -
minIntrinsicHeightэлементаDividerравно 0, поскольку он не занимает место, если не заданы никакие ограничения. - Параметр
TextminIntrinsicHeightопределяет минимальную высоту текста для заданнойwidth. - Таким образом, ограничение
heightэлементаRowстановится равным максимальнойminIntrinsicHeightэлементаText. - Затем
Dividerрасширяет своюheightдоheightзаданногоRow.
Внутренние параметры в ваших пользовательских макетах
При создании пользовательского Layout или модификатора layout автоматически рассчитываются внутренние размеры на основе приблизительных значений. Поэтому расчеты могут быть некорректными для всех макетов. Данные API предоставляют возможности для переопределения этих значений по умолчанию.
Чтобы задать внутренние параметры размеров вашего пользовательского Layout , переопределите значения minIntrinsicWidth , minIntrinsicHeight , maxIntrinsicWidth и maxIntrinsicHeight интерфейса 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. } ) }
При создании собственного модификатора layout переопределите соответствующие методы в интерфейсе 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. }
Рекомендуем вам
- Примечание: текст ссылки отображается, когда JavaScript отключен.
- Пользовательские макеты {:#custom-layouts}
- Линии выравнивания в Jetpack Compose
- Фазы композиции Jetpack