Jetpack Compose Column: почему центрирование не работает и как исправить

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему 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", запомните этот алгоритм:

  1. Проверьте размер Column. Есть ли Modifier.fillMaxSize() или Modifier.fillMaxHeight()? Если нет — центрирование по вертикали не сработает.
  2. Укажите horizontalAlignment. Если хотите центрировать по горизонтали — обязательно добавьте horizontalAlignment = Alignment.CenterHorizontally в конструктор Column.
  3. Не злоупотребляйте IntrinsicSize. Он часто ломает вертикальное центрирование.
  4. Проверьте вложенность. Каждая Column должна иметь свои настройки выравнивания.
  5. Используйте

Блоги

Рекомендаций по книгам