Введение
В этой статье будет пример контейнера с добавлением новых элементов во время композиции. В частности разделителей.
Эта статья поделена на 2 части. Перед чтением этой статьи советую прочитать первую часть.
Добавление разделителей
У нас нет способа добавить разделители во время расстановки содержимого контейнера, поэтому мы должны добавить их заранее. После, зная их количество, на моменте расстановки элементов мы отделим их от остальных.
Считать количество элементов мы будем весьма костыльно, но тем не менее удобно:
@Composable
fun rememberElementsCount(content: @Composable () -> Unit) : State<Int?> {
val result : MutableState<Int?> = remember { mutableStateOf(null) }
Layout(
modifier = Modifier.size(0.dp),
content = content,
) { measurables, _ ->
result.value = measurables.size
layout(0, 0) {}
}
return result
}
Так как Compose не гарантирует порядка композиции, мы не можем быть уверены, что result будет установлен до выхода из функции, из‑за чего нам приходится использовать опциональные значения.
Теперь мы можем отделять изначальное содержимое от разделителей, добавленных нами:
@Composable
private fun DividerLayout(
modifier: Modifier = Modifier,
dividerCount: Int,
divider: @Composable () -> Unit = { androidx.compose.material.Divider() },
content: @Composable () -> Unit,
...
) {
Layout(
modifier = modifier,
content = {
content()
repeat(dividerCount) {
divider()
}
},
) { measurables, constraints ->
val contentPlaceables = measurables.dropLast(dividerCount).map { it.measure(constraints) }
val dividerPlaceables = measurables.takeLast(dividerCount).map { it.measure(constraints) }
measure(constraints, contentPlaceables, dividerPlaceables, ...) // Какая-то функция расстановки элементов контейнера
}
}
Имея их раздельно, не составит труда написать функцию measure. Результат будет выглядеть так:
Увы, из‑за необходимости в рекомпозиции для работы, этот контейнер не будет работать в предпросмотре. Если вы знаете, как сделать это без костыля с пустым Layout, добро пожаловать в комментарии.
Вместо послесловия
Изначально статья была названа продвинутой, так как в неё должны были рассматриваться все стандартные параметры других контейнеров, такие как Alignment, Arrangement и т. п. Но оказалось, что это весьма просто, и писать там не о чем. Поэтому она была переименована в вторую часть.
Если есть что‑то, что не упомянутое в статье и не являющиеся понятным в реализации, пишите в комментарии, и я напишу 3 часть статьи.