Какая функция позволяет сделать свой Layout в Compose

Ответ

Layout — это низкоуровневая функция в Jetpack Compose, позволяющая создать кастомный лейаут с нуля. Она принимает content и измеряет/размещает его по своим правилам.

Пример:

@Composable
fun CustomLayout(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        content = content,
        modifier = modifier
    ) { measurables, constraints ->
        // 1. Измеряем дочерние элементы
        val placeables = measurables.map { it.measure(constraints) }

        // 2. Вычисляем размер лейаута
        val width = placeables.sumOf { it.width }
        val height = placeables.maxOfOrNull { it.height } ?: 0

        // 3. Размещаем дочерние элементы
        layout(width, height) {
            var x = 0
            placeables.forEach { placeable ->
                placeable.placeRelative(x = x, y = 0)
                x += placeable.width
            }
        }
    }
}

Здесь мы создаем горизонтальный лейаут, размещая элементы друг за другом.

Ответ 18+ 🔞

Ну ты смотри, какие дела творятся. Вот сидишь ты, такой весь из себя современный разработчик, с джавой и котлином на короткой ноге, а тут бац — и тебе вдруг понадобилось нарисовать интерфейс, который стандартными штуками не соберёшь. Ёпта, ну и что делать? Правильно, лезть в дебри и писать свой лейаут с блэкджеком и... ну, сами понимаете.

Так вот, Layout в Compose — это, по сути, твой пропуск в этот адский цех. Функция низкоуровневая, голая, как сосиска. Берёшь её и с нуля начинаешь городить свой порядок. Никаких Row или Column тебе в помощь — только твой мозг, руки и эта самая Layout.

Смотри, как это выглядит, а то я чувствую, у тебя уже волнение ебать начинает подкатывать.

@Composable
fun CustomLayout(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        content = content,
        modifier = modifier
    ) { measurables, constraints ->
        // 1. Измеряем дочерние элементы
        val placeables = measurables.map { it.measure(constraints) }

        // 2. Вычисляем размер лейаута
        val width = placeables.sumOf { it.width }
        val height = placeables.maxOfOrNull { it.height } ?: 0

        // 3. Размещаем дочерние элементы
        layout(width, height) {
            var x = 0
            placeables.forEach { placeable ->
                placeable.placeRelative(x = x, y = 0)
                x += placeable.width
            }
        }
    }
}

Видишь эту конструкцию? Это же, блядь, чистая магия, обёрнутая в синтаксис. Сейчас разжую.

Первым делом, ты объявляешь свою функцию. В неё прилетает content — это твои будущие детки, которые внутри этого лейаута будут сидеть. Дальше вызываешь Layout, суёшь туда этот контент и модификатор, а потом начинается самое интересное — лямбда.

В этой лямбде тебе на блюдечке приносят две штуки: measurables и constraints. Measurables — это список твоих детей, но ещё не измеренных, диких таких. А constraints — это ограничения от родителя, типа "сюда влезай, а дальше нельзя".

Дальше три шага, проще некуда, хоть и звучит страшно.

Шаг первый: измерение. Берёшь каждого ребёнка из measurables и говоришь ему: "Ну-ка, меряйся, хули ты тут стоишь!" — через it.measure(constraints). На выходе получаешь placeables — это уже измеренные сущности, с известными шириной и высотой, готовые к размещению.

Шаг второй: самоопределение. Тебе надо решить, какого же размера будет твой собственный лейаут. В примере выше — примитив до безобразия. Ширина — это сумма ширин всех детей. Высота — это высота самого высокого ребёнка. Получается такой горизонтальный ряд. Но тут-то и кроется вся сила: можешь вычислять размер как угодно, хоть по луне привязывай. Это твоё царство.

Шаг третий: расстановка по полочкам. Вызываешь layout(width, height), передав вычисленные размеры, и внутри уже начинаешь детей расставлять методом placeRelative. В примере просто ставят их в ряд, сдвигая x на ширину предыдущего. Но опять же — можешь хоть по кругу распихать, хоть в шахматном порядке. Полная воля.

Вот и вся наука. Выглядит, конечно, как инструкция к сборке космического корабля из говна и палок, но если вникнуть — логика проще пареной репы. Главное — не бздеть и попробовать. Сначала будет ощущение, что ты пытаешься засунуть диван в хрущёвский лифт, но потом втянешься. Удачи, чувак.