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