Composable Function — це фундаментальна одиниця користувацького інтерфейсу в Jetpack Compose, яка визначає, як має виглядати та поводитися частина екрану. Кожна така функція позначена анотацією @Composable та виконується в спеціальному контексті, що дозволяє Compose відстежувати залежності та автоматично перебудовувати UI при зміні даних. За даними Google Android Developers, 2026, правильна побудова функцій Composable безпосередньо впливає на продуктивність додатка та ефективність рекомпозиції.
Головне
Composable Function — це функція в мові Kotlin, позначена анотацією @Composable, яка описує частину користувацького інтерфейсу декларативним способом. Замість створення та налаштування об’єктів View через Java-код або XML-розмітку, розробник просто пише, як UI має виглядати при кожному стані даних.
Основна відмінність між функцією Composable та традиційною View-системою Android полягає в моделі оновлення. У класичному підході розробник вручну викликав findViewById, змінював текст через setText та керував видимістю через setVisibility. Composable Function звільняє від цієї рутини: коли дані змінюються, система сама визначає, які функції потрібно перезапустити, і виконує лише їх.
Компілятор Kotlin, обробляючи анотацію @Composable, генерує додатковий код, який інтегрує функцію в механізм композиції. Цей код включає читання та запис у слоти — спеціальні комірки пам’яті, що зберігають стан та параметри кожної функції Composable в поточному UI-дереві. Завдяки цій інтеграції Compose знає, які функції залежать від яких даних.
Синтаксис функції Composable максимально лаконічний: достатньо додати @Composable перед ключовим словом fun. Функція може приймати будь-які параметри, включати інші виклики Composable в своєму тілі та використовувати конструкції Kotlin — умови, цикли, when-вирази — для умовного відображення UI.
@Composable
fun ProductItem(
product: Product,
modifier: Modifier = Modifier,
onAddToCart: () -> Unit
) {
Card(modifier = modifier.padding(8.dp)) {
Row(modifier = Modifier.fillMaxWidth().padding(12.dp),
verticalAlignment = Alignment.CenterVertically) {
Column(modifier = Modifier.weight(1f)) {
Text(text = product.name, style = MaterialTheme.typography.titleMedium)
Text(text = "${product.price}", color = MaterialTheme.colorScheme.primary)
}
Button(onClick = onAddToCart) {
Text("Додати до кошика")
}
}
}
}
У цьому прикладі функція Composable ProductItem приймає об’єкт Product, модифікатор та колбек. Усі три параметри імутабельні, що гарантує предбачувану поведінку при рекомпозиції. Модифікатор передається як параметр із значенням за замовчуванням — це стандартна практика, яка дозволяє викликаючій стороні налаштовувати відступи та розміри.
Всередині функції Composable використовуються вбудовані компоненти Material Design (Text, Button, Card, TextField) або фундаментальні примітиви (Canvas, Layout). Кожен компонент приймає параметри для налаштування зовнішнього вигляду та поведінки, а також один або кілька модифікаторів через параметр modifier.
Модифікатори — це ланцюг функцій, які змінюють розмір, позицію, обробку подій та зовнішній вигляд компонента. Порядок модифікаторів у ланцюзі має значення: clickable.semantics працює інакше, ніж semantics.clickable, а padding.background зафарбовує і область, і фон, включаючи padding, що критично при проектуванні.
Всередині функції Composable можна використовувати умови if та when для умовного відображення частин UI, а також цикли for для динамічних списків. Усі ці конструкції працюють природнім чином, оскільки Kotlin — повноцінна мова програмування. Однак важливо пам’ятати: якщо умова або цикл містить виклики функцій Composable, вони також беруть участь у рекомпозиції.
@Composable
fun ProductList(
products: List<Product>,
modifier: Modifier = Modifier
) {
LazyColumn(modifier = modifier) {
items(products, key = { it.id }) { product ->
ProductItem(
product = product,
onAddToCart = { /* add to cart */ }
)
}
}
}
Розглянемо приклад екрану пошуку товарів з використанням кількох функцій Composable. Тут показані типові патерни: поле введення зі станом, фільтрація списку, обробка порожнього результату та завантаження.
data class Product(
val id: String,
val name: String,
val price: Double,
val category: String
)
@Composable
fun SearchScreen() {
var query by remember { mutableStateOf("") }
val products = remember(query) { getFilteredProducts(query) }
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
OutlinedTextField(
value = query,
onValueChange = { query = it },
label = { Text("Пошук товарів") },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
when (products) {
is Loading -> CircularProgressIndicator()
is Empty -> Text("Результатів не знайдено")
is Result -> LazyColumn {
items(products.items, key = { it.id }) { product ->
ProductItem(product = product, onAddToCart = {})
}
}
}
}
}
Цей приклад демонструє одразу кілька ідіом: remember для збереження стану пошукового запиту, remember(query) для фільтрації з ключем, when для трьох станів UI та LazyColumn для ефективного відображення списку.
Функції Composable приймають параметри так само, як і звичайні функції Kotlin, але з однією важливою відмінністю: параметром може бути інша функція Composable, передана через лямбда з анотацією @Composable. Цей механізм називається Slot API і є основним патерном для створення повторно використовуваних контейнерів.
Slot API вирішує проблему, яку в традиційній View-системі вирішували через ViewGroup та програмне додавання дочірніх View. Замість методів addView Compose використовує content-лямбди — останній параметр з типом @Composable () -> Unit. Викликаюча сторона передає будь-який UI у цю лямбду, а контейнер лише визначає його розташування.
Параметри функцій Composable можуть мати значення за замовчуванням, що спрощує їх використання в різних контекстах. Рекомендується робити обов’язковими лише ті параметри, без яких функція не може виконати своє завдання, а для інших надавати розумні значення за замовчуванням.
| Параметр | Тип | Приклад |
|---|---|---|
| Обов’язковий | Будь-який тип | name: String |
| Необов’язковий | Із значенням за замовчуванням | modifier: Modifier = Modifier |
| Content | @Composable () -> Unit | content: @Composable () -> Unit |
| Callback | Лямбда без @Composable | onClick: () -> Unit |
У спільноті Compose склалося кілька усталених ідіом, які роблять функції Composable більш читаними та предбачуваними. Перша — State Hoisting: стан підіймається на рівень вище, а функція Composable отримує його через параметри. Це робить функцію чистою та повторно використовуваною в різних контекстах.
Друга ідіома — параметри Event-driven. Замість передачі ViewModel або useCase у функцію Composable, передаються лише конкретні колбеки: onSave, onDelete, onNavigateToDetail. Це знижує зв’язаність та спрощує тестування.
Третя ідіома — CompositionLocal для передачі спільних даних через дерево композиції. Тема, щільність екрану, поточний Route — усе це передається через CompositionLocal, уникаючи ланцюжків параметрів через десятки функцій Composable. Однак зловживати CompositionLocal не варто: явні параметри завжди кращі за неявні залежності.
// State Hoisting: стан піднято до батьківської функції
@Composable
fun CounterDisplay(
count: Int,
onIncrement: () -> Unit
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "Лічильник: $count", style = MaterialTheme.typography.headlineLarge)
Button(onClick = onIncrement) {
Text("+1")
}
}
}
// Використання з State Hoisting
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }
CounterDisplay(
count = count,
onIncrement = { count++ }
)
}
Часто задавані питання
Так, return допустимий, але з обережністю. Compose оптимізує рекомпозицію на рівні окремих функцій, а ранній return може порушити цю оптимізацію. Краще використовувати умовні оператори if або when всередині тіла функції.
В Kotlin Unit — це об’єкт-синглтон, а не порожній тип. Функції Composable повертають Unit, що технічно означає, що вони повертають сам об’єкт Unit. Однак на практиці це не має значення.
Передавати змінювані колекції можна, але це погана практика. Якщо колекція зміниться, Compose не дізнається про це, оскільки посилання на об’єкт залишається тим самим. Використовуйте незмінні списки або mutableStateListOf для відстежуваних змін.
Для налагодження використовуйте Android Studio з Layout Inspector, який показує поточне дерево функцій Composable, значення параметрів та причини рекомпозиції. Звичайний налагоджувач Kotlin також працює.
Функція Composable завжди повертає Unit, тому тип повернення не вказується. Спроба повернути інший тип викличе помилку компіляції, оскільки анотація @Composable несумісна з типами повернення, відмінними від Unit.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також