Почему Column не слушается? Проклятие центрирования в Jetpack Compose
Вы когда-нибудь сидели ночью с чашкой кофе, писали код на Kotlin для Jetpack Compose и вдруг замечали, что ваша Column упрямо отказывается центрировать содержимое? Ты добавляешь Modifier.align(Alignment.CenterHorizontally) — а текст всё равно прилипает к левому краю. Знакомо?
Эта проблема — настоящий хит на Stack Overflow. Тысячи разработчиков (и я в их числе) бились головой об экран, пытаясь понять, куда делся "gravity center". В этой статье мы разберём топ ошибок, которые превращают вашу Column в неуправляемый список, и научимся их избегать. Готовьтесь: будет много кода, живых примеров и никакой воды.
Ошибка №1: Путаница между Column и Row
Первая и самая распространённая ловушка — перенос привычек из классического Android XML. Там у LinearLayout был атрибут gravity="center". В Compose всё иначе.
Ключевое отличие: Column располагает элементы вертикально. Поэтому "центрирование по горизонтали" — это не свойство самой Column, а поведение её дочерних элементов. Если вы пишете:
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Привет, мир!")
}
Тут horizontalAlignment работает, но только если сам Text не ограничен по ширине. А если у вас Modifier.fillMaxWidth() на дочернем элементе — центрирование сломается. Почему? Потому что элемент растягивается на всю ширину, и центрировать внутри него уже нечего.
Ошибка №2: Modifier.align() вместо horizontalAlignment
Вот классический код-ловушка, который гуляет по Stack Overflow:
Column(
modifier = Modifier.fillMaxSize()
) {
Text(
text = "Я должен быть по центру",
modifier = Modifier.align(Alignment.CenterHorizontally)
)
}
На первый взгляд — логично. Но это не сработает, если у Column не задан horizontalAlignment. Дело в том, что Modifier.align() — это модификатор для Box и ColumnScope. Он доступен только внутри Column, но работает в паре с horizontalAlignment. Если последний не указан, align просто игнорируется.
Как исправить:
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally // обязательно!
) {
Text(
text = "Теперь я по центру",
modifier = Modifier.align(Alignment.CenterHorizontally) // опционально
)
}
Ошибка №3: Забываем про Arrangement для вертикали
Часто разработчики хотят центрировать содержимое Column по вертикали (по оси Y). Тут в игру вступает verticalArrangement:
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Центр вселенной")
Button(onClick = { }) { Text("Кнопка") }
}
Но есть нюанс: Arrangement.Center сработает, только если Column занимает всю высоту экрана (Modifier.fillMaxSize() или Modifier.height(IntrinsicSize.Min)). Если высота Column равна сумме высот дочерних элементов — центрировать будет некуда.
Ошибка №4: IntrinsicSize и неожиданное поведение
Иногда вы добавляете Modifier.height(IntrinsicSize.Min), чтобы Column сжималась по содержимому. И тут центрирование по вертикали ломается:
Column(
modifier = Modifier
.fillMaxWidth()
.height(IntrinsicSize.Min),
verticalArrangement = Arrangement.Center
) {
Text("Текст 1")
Text("Текст 2")
}
Проблема: IntrinsicSize.Min делает высоту Column равной минимальной высоте содержимого. Вертикального пространства для центрирования не остаётся. Решение — либо убрать IntrinsicSize, либо задать фиксированную высоту, либо использовать Box с Modifier.wrapContentSize(Alignment.Center).
Ошибка №5: Вложенные Column и потеря контекста
Когда у вас есть Column внутри Column, модификатор align работает только для ближайшего родителя:
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Column {
Text(
text = "Я не по центру!",
modifier = Modifier.align(Alignment.CenterHorizontally) // ошибка
)
}
}
Внутренняя Column не имеет horizontalAlignment, поэтому Modifier.align игнорируется. Исправление: либо передайте horizontalAlignment во внутреннюю Column, либо используйте Modifier.fillMaxWidth() с TextAlign.Center.
Ошибка №6: Путаница между Alignment и Arrangement
Это, пожалуй, самая частая причина головной боли. Запомните раз и навсегда:
- Alignment — для выравнивания дочерних элементов внутри Column (по горизонтали —
Alignment.CenterHorizontally, по вертикали —Alignment.Top,Alignment.Bottom). - Arrangement — для распределения пространства между элементами (по вертикали —
Arrangement.Center,Arrangement.SpaceBetweenи т.д.).
Вот наглядный пример путаницы:
// Ошибка: пытаемся использовать Arrangement для горизонтали
Column(
modifier = Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.Center // такой параметр есть только в Row!
) {
Text("Ошибка компиляции")
}
Правильно: Arrangement для Column работает только по вертикали, а для горизонтали — Alignment.
Как не наступать на эти грабли: чек-лист
Чтобы больше никогда не гуглить "Column gravity center", запомните этот алгоритм:
- Проверьте размер Column. Есть ли
Modifier.fillMaxSize()илиModifier.fillMaxHeight()? Если нет — центрирование по вертикали не сработает. - Укажите horizontalAlignment. Если хотите центрировать по горизонтали — обязательно добавьте
horizontalAlignment = Alignment.CenterHorizontallyв конструктор Column. - Не злоупотребляйте IntrinsicSize. Он часто ломает вертикальное центрирование.
- Проверьте вложенность. Каждая Column должна иметь свои настройки выравнивания.
- Используйте