Jetpack Compose — це сучасний декларативний тулкіт для побудови інтерфейсів Android на Kotlin. Розробник описує UI через composable функції, а тулкіт автоматично перемальовує лише змінені частини. За даними Android Developers (2026), Jetpack Compose працює на Android 5.0 (API 21) і вище, підтримує Material Design 3 та досягає 120 FPS на пристроях середнього сегмента завдяки власній системі Recomposition — розумному diff-алгоритму, що оновлює лише змінені віджети.
Головне
Jetpack Compose — це декларативний фреймворк від Google для побудови користувацьких інтерфейсів Android, анонсований у 2019 році та досягнутий стабільного релізу в 2021-му. На відміну від старої View System (XML-розмітка + Activity/Fragment), Compose використовує анотовані Kotlin-функції — @Composable. Інтерфейс описується цілком на Kotlin: немає розділення на XML та код. Це усунуло клас помилок, пов'язаних з неспівпадінням id у XML та Kotlin (type-safe synthetic не рятував при рефакторингу).
Compose побудований на власній системі рендерингу — Canvas, не прив'язаній до View-ієрархії. Кожен Composable малює себе на Canvas напряму, оминаючи onMeasure/onDraw View System. Це дає приріст продуктивності на складних екранах: у тестах Google (2023) екран на Compose з 200 елементами відмальовувався на 40% швидше за аналогічний на RecyclerView + ViewHolder.
Для роботи Compose потрібен minSdk 21 (Android 5.0) та Kotlin 1.9+. Compose BOM (Bill of Materials) синхронізує версії всіх бібліотек Compose. Фреймворк сумісний з існуючим кодом на View System: Compose вбудовується через ComposeView у XML-розмітку, а старі View — через AndroidView у Compose-ієрархію. За даними Google Play Console (2025), Android 5.0+ покриває 97% активних пристроїв, тому сумісність не є обмеженням для більшості проєктів.
@Composable — це анотація, що перетворює звичайну Kotlin-функцію на будівельний блок UI. Composable функція описує, як має виглядати фрагмент інтерфейсу — текст, кнопка, список. Замість повернення значення функція емітує (emits) UI-компоненти в композицію. Це схоже на генератор: кожна функція додає елементи на екран при виклику.
@Composable
fun ProfileCard(name: String, avatarUrl: String) {
Card(
modifier = Modifier.fillMaxWidth().padding(16.dp),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surface
)
) {
Row(verticalAlignment = Alignment.CenterVertically) {
AsyncImage(
model = avatarUrl,
contentDescription = "Аватар",
modifier = Modifier.size(48.dp).clip(CircleShape)
)
Spacer(Modifier.width(12.dp))
Text(
text = name,
style = MaterialTheme.typography.titleMedium
)
}
}
}
Функція ProfileCard приймає параметри (name, avatarUrl) та емітує Card → Row → AsyncImage + Text. Композиція — це дерево емітованих компонентів за один прохід. Якщо параметри не змінилися, Compose пропускає виклик функції (recomposition skip). Якщо змінився лише name, буде викликаний лише Text, решта елементів не буде перемальована. Такий intelligent recomposition — ключова перевага продуктивності Compose перед ручною оптимізацією View System.
Composable функції активно використовують слоти — trailing lambda, content: @Composable (() -> Unit). Це дозволяє створювати контейнери: Card, Column, Row приймають content-лямбду, і вміст вбудовується на місце слота. Slot API замінив XML-атрибути на кшталт android:layout_gravity — тепер розташування дочірніх елементів задається Kotlin-кодом всередині контент-блоку.
Стан у Compose — це будь-яке значення, яке може змінюватися з часом. Коли стан змінюється, Compose планує recomposition для всіх компонентів, що читають цей стан. Механізм нагадує React hooks: mutableStateOf повертає MutableState<T>, читання .value автоматично підписує поточну композицію на зміни.
@Composable
fun CounterExample() {
var count by remember { mutableStateOf(0) }
Column(modifier = Modifier.padding(16.dp)) {
Text("Натиснуто: $count")
Button(onClick = { count++ }) {
Text("Збільшити")
}
}
}
@Composable
fun UserScreen(viewModel: UserViewModel) {
val userName by viewModel.userName.collectAsState()
Text("Користувач: $userName")
}
remember зберігає значення між рекомпозиціями — інакше mutableStateOf створювався б заново при кожному оновленні UI. collectAsState() конвертує StateFlow з ViewModel у Compose-сумісний стан. Рекомендація — для екранного стану використовувати ViewModel з StateFlow, для локального (наприклад, розгорнута картка) — mutableStateOf. Це розділення відповідає принципу «розумні/тупі» компоненти.
State Hoisting — паттерн винесення стану з дочірнього компонента в батьківський. Батько передає значення та callback через параметри, дочірній викликає callback при зміні. Батько зберігає mutableStateOf, дочірній — лише параметри. Це робить компонент перевикористовуваним і тестованим: той самий TextField можна використовувати з будь-яким джерелом даних.
Modifier — це об'єкт, що описує трансформації Composable: розмір, відступи, фон, обробку кліків, анімацію, скрол. Модифікатори застосовуються через ланцюжок викликів: Modifier.fillMaxWidth().padding(16.dp).background(Color.Blue).clickable { }. Кожен виклик повертає новий Modifier з доданою властивістю — жодної мутації оригінального об'єкта.
Порядок модифікаторів важливий. Modifier.padding(16.dp).background(Color.Blue) зафарбовує область з відступом. Modifier.background(Color.Blue).padding(16.dp) зафарбовує внутрішній прямокутник, а відступ залишається прозорим. Механіка схожа на CSS box model: padding спочатку → background працює як margin + background; background спочатку → padding — як background + внутрішній відступ. Розробнику достатньо запам'ятати: padding спочатку = зовнішній відступ, padding потім = внутрішній.
Якщо вбудованих модифікаторів недостатньо, створюється кастомний через Modifier.composed { ... } або Modifier.then(). Всередині кастомного модифікатора можна використовувати layout-вимірювання (Modifier.layout { measurable, constraints -> ... }), малювання (Modifier.drawWithContent { ... }), жести (Modifier.pointerInput { ... }). Приклад: модифікатор для пульсуючої анімації при натисканні — вимірює розмір, при кліку запускає scale-анімацію через animateFloatAsState.
Для анімацій Compose надає animate*AsState (animateFloatAsState, animateColorAsState, animateDpAsState) — значення анімуються між старим і новим станом при зміні. Якщо потрібно анімувати появу/зникнення — AnimatedVisibility та AnimatedContent з вбудованими переходами (fade, slide, expand). Всі анімації працюють на graphics layer, не викликаючи зайву композицію.
Composable функції не повинні виконувати побічні дії безпосередньо (мережеві запити, таймери, підписки) — вони викликаються на кожній рекомпозиції, що призведе до дублювання запитів. Для побічних ефектів Compose надає сімейство Effect-функцій: LaunchedEffect запускає корутину при вході в композицію та скасовує при виході, DisposableEffect — для ресурсів, що потребують явного очищення (сенсори, BroadcastReceiver).
@Composable
fun SensorReader() {
val context = LocalContext.current
var sensorValue by remember { mutableStateOf(0f) }
DisposableEffect(Unit) {
val sensor = registerSensorListener(context) { value ->
sensorValue = value
}
onDispose {
unregisterSensorListener(sensor)
}
}
Text("Значення: $sensorValue")
}
@Composable
fun UserGreeting(userId: String) {
LaunchedEffect(userId) {
val profile = api.fetchProfile(userId)
// оновлення стану
}
}
LaunchedEffect(userId) перезапускається, якщо userId змінився — попередня корутина скасовується, нова запускається з новим userId. Це позбавляє від ручного керування скасуванням запитів. DisposableEffect(Unit) — ефект з фіксованим ключем Unit, спрацьовує при вході в композицію та викликає onDispose при виході. SensorReader реєструє слухача та відписується при виході з екрана — без ризику витоку.
Якщо корутину потрібно запустити не при вході в композицію, а за подією (натискання кнопки), використовується rememberCoroutineScope(). Він повертає CoroutineScope, прив'язаний до життєвого циклу Composable, що не потребує DisposableEffect. Приклад: запуск мережевого запиту при кліку на кнопку — scope.launch { viewModel.loadData() }.
Вибір між Compose та View System — головне архітектурне питання Android-розробника в 2026 році. Обидві технології підтримуються Google, але Compose — основний напрям, на який Google витрачає ресурси. View System отримує лише критичні виправлення і не розвивається. Різниця проявляється в синтаксисі, керуванні станом, продуктивності та часі розробки.
| Аспект | Jetpack Compose | View System |
|---|---|---|
| Опис UI | Kotlin @Composable функції | XML-розмітка + Activity/Fragment |
| Стан | mutableStateOf, StateFlow, автоматичне перемальовування | findViewById, вручну: setText, notifyDataSetChanged |
| Продуктивність | Intelligent recomposition, Canvas-рендеринг | View-ієрархія, measure/layout/draw |
| Анімації | animate*AsState, AnimatedVisibility, вбудовані | ValueAnimator, ObjectAnimator, Transition |
| Сумісність | minSdk 21, ComposeView/AndroidView мости | Всі версії, будь-яка |
| Розмір APK | +3–5 МБ на Compose | Без накладних витрат |
Для нових проєктів Google рекомендує Jetpack Compose як стандарт UI-розробки. View System залишається для підтримки коду, написаного до 2021 року, та випадків, коли потрібен мінімальний розмір APK (наприклад, для ринків, що розвиваються, з пристроями початкового рівня). Compose скорочує обсяг UI-коду на 30–50% порівняно з View System завдяки декларативному синтаксису та вбудованій анімації.
Часті запитання
Так, через ComposeView у XML-розмітці. Додайте dependency на Compose та оберніть екран або його частину в ComposeView { MyComposable() }. Міграція поекранна.
Причина — стан піднімається занадто високо або використовуються змінювані об'єкти. Виправлення: derivedStateOf для похідних даних та remember для стабільних посилань.
Використовуйте LazyColumn (аналог RecyclerView). Елементи створюються та перевикористовуються в міру скролу. Для складних списків з різними типами комірок — LazyColumn { items(items, key = { it.id }) { ... } }.
Ні, можна починати одразу з Compose. Знання View System допомагає при підтримці легасі-коду, але Compose — самостійна екосистема зі своєю документацією та паттернами.
Так, Material 3 — стандартна тема Compose з 2023 року. Підключається через implementation("androidx.compose.material3:material3"). Material 2 вважається застарілим.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.