Данфа

Контейнеры верстки в Jetpack Compose

В Jetpack Compate интерфейс строится не из XML-файлов, а из функций Kotlin. Чтобы управлять положением кнопок, текстов и картинок, используются специальные контейнеры — Composable-функции, которые диктуют правила расположения своих «детей».

Разберем всю иерархию: от базовых строительных блоков до мощных инструментов для сложных экранов.

Column() — Вертикальный стек


Располагает элементы друг под другом, сверху вниз. Это прямой аналог LinearLayout(vertical).

Для чего нужен:
  • Формы регистрации и экраны настроек.
  • Ленты постов, где каждый элемент идет за другим.
  • Группировка заголовка, текста и кнопки.

Пример:
@Composable
fun UserProfile() {
    Column(
        modifier = Modifier.padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally // Центрируем всё по ширине
    ) {
        Text(text = "Алексей", style = MaterialTheme.typography.headlineSmall)
        Text(text = "@prizrak_dev", color = Color.Gray)
        Spacer(modifier = Modifier.height(12.dp)) //
...

Уведомления в Android: Как они устроены на самом деле

Если вы когда-нибудь писали мессенджер или любое приложение, которому нужно сообщать пользователю о новых событиях, вы рано или поздно сталкиваетесь с тем, что уведомления в Android — это не «показать текст в шторке», а целая система с собственными правилами. В этой статье я разберу, как уведомления устроены внутри, почему идентификация пушей — это отдельная инженерная задача, и какие решения здесь работают надёжнее всего. Материал не привязан к конкретному проекту, но примеры будут на Kotlin.

Атомарность уведомления


Каждое уведомление в шторке — это объект с двумя ключами: тегом (строка, необязательная) и ID (целое число, обязательное). Именно пара «тег — ID» определяет уникальность. Это значит, что два уведомления с одинаковым ID, но разными тегами, спокойно сосуществуют, а два уведомления с одинаковой парой заменяют друг друга.

Это первое место, где начинающие разработчики теряются. Типичный сценарий: приложение шлёт уведомления о новых сообщениях, и разработчик генерирует для...

Kotlin: Как вывести данные для проверки

При написании приложения может потребоваться проверить данные, как они были обработаны. Для этого, за частую, достаточно их просто увидеть. В этом нам поможет класс Gson. Чтобы его использовать, необходимо импортировать:
import android.util.Log

Если, по каким то причинам его у вас до сих пор нет, добавляем в "build.gradle.kts":
implementation("com.google.code.gson:gson:xx.xx.xx")

  • xx.xx.xx: Указывайте актуальную версию.

После чего, если потребуется, пересоберите проект. И выводите нужные данные так:
Gson().toJson(data)

В лог выводим так:
Log.d("Data", Gson().toJson(data))

Импорт логирования:
import android.util.Log

В логе увидите строку с данными.

...

Kotlin: Стандартные индикаторы загрузки

В Jetpack Compose есть несколько стандартных индикаторов загрузки:
  1. CircularProgressIndicator: Классический круговой индикатор.
  2. LinearProgressIndicator: Линейный индикатор.
  3. ActivityIndicator: Простой вращающийся индикатор.

Примеры их использования:
// Круговой индикатор
CircularProgressIndicator(
    modifier = Modifier
        .size(40.dp)
        .padding(16.dp),
    color = MaterialTheme.colorScheme.primary
)

// Линейный индикатор
LinearProgressIndicator(
    progress = 0.5f, // значение от 0 до 1
    modifier = Modifier
        .height(4.dp)
        .fillMaxWidth()
        .padding(16.dp)
)

// Простой индикатор активности
ActivityIndicator(
    modifier = Modifier
        .size(40.dp)
        .padding(16.dp),
    color = MaterialTheme.colorScheme.primary
)


Дополнительные возможности настройки:
  • Изменение размера через модификатор size().
  • Настройка цвета через параметр color.
  • Анимация прогресса для LinearProgressIndicator.
  • Стилизация через темы Material
...

Kotlin: Как получить часовой пояс устройства

В Kotlin можно получить часовой пояс пользователя несколькими способами.

Через TimeZone


val timeZone = TimeZone.getDefault()
val timeZoneId = timeZone.id // например: "Europe/Moscow"
val offset = timeZone.rawOffset / (1000 * 60 * 60) // смещение в часах

Через ZoneId (Рекомендуемый способ)


import java.time.ZoneId

val zoneId = ZoneId.systemDefault()
val zoneIdString = zoneId.toString() // например: "Europe/Moscow"

Через Calendar


import java.util.Calendar

val calendar = Calendar.getInstance()
val timeZone = calendar.timeZone
val offset = timeZone.getRawOffset()

Через LocalDateTime


import java.time.LocalDateTime
import java.time.ZoneId

val currentTime = LocalDateTime.now(ZoneId.systemDefault())

Примеры использования



Получение названия часового пояса
fun getUserTimeZone(): String {
    return ZoneId.systemDefault().toString()
}

Получение смещения от UTC
fun getTimeZoneOffset(): Int {
    val zone =
...