Одно из правил Compose заключается в том, что дочерние элементы можно измерять только один раз. Если измерить их дважды, возникнет исключение времени выполнения. Однако бывают случаи, когда вам нужна информация о ваших детях, прежде чем измерять их.
Внутренние размеры позволяют запрашивать дочерние элементы до того, как они будут фактически измерены.
Для composable-функции можно запросить 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 с текстом, нарисованным в одной строке.
Внутренние мотивы в действии
Вы можете создать composable-функцию, которая отображает на экране два текста, разделенных разделителем:
Для этого используйте Row с двумя composable-функциями 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 определяется следующим образом:
minIntrinsicHeightcomposable-функцииRow– это максимальное значение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 Compose