Composable Function: что это, синтаксис функции и правила

Автор: IT Sectr Опубликовано: 2026-06-27 Время чтения: 8 мин

Composable Function — это фундаментальная единица пользовательского интерфейса в Jetpack Compose, которая определяет, как должна выглядеть и вести себя часть экрана. Каждая такая функция помечена аннотацией @Composable и выполняется в специальном контексте, позволяющем Compose отслеживать зависимости и автоматически перестраивать UI при изменении данных. По данным Google Android Developers, 2026, правильное построение Composable-функций напрямую влияет на производительность приложения и эффективность рекомпозиции.

Главное

  • Composable Function — функция Kotlin с аннотацией @Composable, строящая UI-дерево
  • Параметры должны быть иммутабельными, а изменяемые данные — через state
  • Вызов возможен только из контекста другой Composable-функции
  • Порядок выполнения не гарантирован — каждая функция должна быть независимой
  • Modifier рекомендуется передавать как параметр для кастомизации

Что такое Composable Function в Jetpack Compose

Composable Function — это функция в языке Kotlin, помеченная аннотацией @Composable, которая описывает часть пользовательского интерфейса декларативным способом. Вместо того чтобы создавать и настраивать View-объекты через Java-код или XML-разметку, разработчик просто пишет, как UI должен выглядеть при каждом состоянии данных.

Основное отличие Composable-функции от традиционной View-системы Android заключается в модели обновления. В классическом подходе разработчик вручную вызывал findViewById, менял текст через setText, управлял видимостью через setVisibility. Composable Function освобождает от этой рутины: при изменении данных система сама определяет, какие функции нужно перезапустить, и выполняет только их.

Компилятор Kotlin, обрабатывая аннотацию @Composable, генерирует дополнительный код, который интегрирует функцию в механизм композиции. Этот код включает в себя чтение и запись в слоты — специальные ячейки памяти, хранящие состояние и параметры каждой Composable-функции в текущем UI-дереве. Благодаря этой интеграции Compose знает, какие функции зависят от каких данных.

Синтаксис объявления Composable-функции

Синтаксис Composable-функции максимально лаконичен: достаточно добавить @Composable перед ключевым словом fun. Функция может принимать любые параметры, включать другие Composable-вызовы в своём теле и использовать Kotlin-конструкции — условия, циклы, when-выражения — для условного отображения UI.

kotlin
@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("Add to cart")
            }
        }
    }
}

В этом примере Composable-функция ProductItem принимает объект Product, модификатор и колбэк. Все три параметра иммутабельны, что гарантирует предсказуемое поведение при рекомпозиции. Модификатор передан как параметр с дефолтным значением — это стандартная практика, позволяющая вызывающей стороне настраивать отступы и размеры.

Компоненты и модификаторы в Composable-функциях

Внутри Composable-функции используются встроенные компоненты Material Design (Text, Button, Card, TextField) или фундаментальные примитивы (Canvas, Layout). Каждый компонент принимает параметры для настройки внешнего вида и поведения, а также один или несколько модификаторов через параметр modifier.

Модификаторы (Modifier) — это цепочка функций, которые изменяют размер, положение, обработку событий и внешний вид компонента. Порядок модификаторов в цепочке имеет значение: clickable.semantics работает не так, как semantics.clickable, а padding.background закрашивает и фон области, включая padding, что критически важно при проектировании.

Внутри Composable-функции можно использовать условия if и when для условного отображения частей UI, а также циклы for для динамических списков. Все эти конструкции работают естественным образом, поскольку Kotlin — полноценный язык программирования. Однако важно помнить: если условие или цикл содержат вызов Composable-функций, они тоже участвуют в рекомпозиции.

kotlin
@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-функций для реальных экранов

Рассмотрим пример экрана поиска товаров с использованием нескольких Composable-функций. Здесь показаны типичные паттерны: поле ввода с состоянием, фильтрация списка, обработка пустого результата и загрузки.

kotlin
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("Search products") },
            modifier = Modifier.fillMaxWidth()
        )

        Spacer(modifier = Modifier.height(16.dp))

        when (products) {
            is Loading -> CircularProgressIndicator()
            is Empty -> Text("No results found")
            is Result -> LazyColumn {
                items(products.items, key = { it.id }) { product ->
                    ProductItem(product = product, onAddToCart = {})
                }
            }
        }
    }
}

Этот пример демонстрирует сразу несколько идиом: remember для сохранения состояния поискового запроса, remember(query) для фильтрации с ключом, when для трёх состояний UI и LazyColumn для эффективного отображения списка. Каждая из этих идиом — результат практического опыта разработки Compose-приложений.

Параметры и Slot API

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 () -> Unitcontent: @Composable () -> Unit
КолбэкЛямбда без @ComposableonClick: () -> Unit

Идиомы Composable-функций в Kotlin

В сообществе Compose сложилось несколько устоявшихся идиом, которые делают Composable-функции более читаемыми и предсказуемыми. Первая — State Hoisting: состояние поднимается на уровень выше, а Composable-функция получает его через параметры. Это делает функцию чистой и переиспользуемой в разных контекстах.

Вторая идиома — Event-driven параметры. Вместо того чтобы передавать в Composable-функцию ViewModel или useCase, передаются только конкретные колбэки: onSave, onDelete, onNavigateToDetail. Это снижает связанность и упрощает тестирование — для теста ProductItem не нужна ViewModel, только лямбда-заглушка.

Третья идиома — CompositionLocal для передачи общих данных через дерево композиции. Тема, плотность экрана, текущий Route — всё это передаётся через CompositionLocal, избегая цепочек параметров через десятки Composable-функций. Однако злоупотреблять CompositionLocal не стоит: явные параметры всегда предпочтительнее неявных зависимостей.

kotlin
// State Hoisting: state lifted to the parent function
@Composable
fun CounterDisplay(
    count: Int,
    onIncrement: () -> Unit
) {
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text(text = "Counter: $count", style = MaterialTheme.typography.headlineLarge)
        Button(onClick = onIncrement) {
            Text("+1")
        }
    }
}

// Usage with State Hoisting
@Composable
fun CounterScreen() {
    var count by remember { mutableStateOf(0) }
    CounterDisplay(
        count = count,
        onIncrement = { count++ }
    )
}

Часто задаваемые вопросы

Можно ли использовать return в Composable-функции?

Да, return допустим, но с осторожностью. Compose оптимизирует рекомпозицию на уровне отдельных функций, а ранний return может нарушить эту оптимизацию. Лучше использовать условные операторы if или when внутри тела функции.

Чем отличается Unit-return от void в Java?

В Kotlin Unit — это объект-синглтон, а не пустой тип. Composable-функции возвращают Unit, что технически означает, что они возвращают сам объект Unit. Однако на практике это не имеет значения — возвращаемое значение игнорируется системой композиции.

Можно ли передавать в Composable-функцию mutableListOf?

Передавать изменяемые коллекции можно, но это плохая практика. Если коллекция изменится, Compose не узнает об этом, так как ссылка на объект осталась той же. Используйте immutable-списки или mutableStateListOf для отслеживаемых изменений.

Как отладить Composable-функцию?

Для отладки используйте Android Studio с Layout Inspector, который показывает текущее дерево Composable-функций, значения параметров и причины рекомпозиции. Также работает обычный отладчик Kotlin — точки останова внутри Composable-функций корректно срабатывают при каждой рекомпозиции.

Обязательно ли указывать return type у Composable-функции?

Composable-функция всегда возвращает Unit, поэтому return type не указывается. Попытка вернуть другой тип вызовет ошибку компиляции, так как аннотация @Composable несовместима с не-Upload возвращаемыми типами.

Итоги

  • Composable Function — декларативный строительный блок UI, помеченный @Composable
  • Параметры должны быть иммутабельными для предсказуемой рекомпозиции
  • Модификаторы и Slot API обеспечивают гибкость и переиспользование без наследования
  • State Hoisting — вынесение состояния наверх для чистоты и тестируемости
  • Event-driven колбэки снижают связанность с ViewModel и бизнес-логикой
  • CompositionLocal используется для общих данных, но явные параметры предпочтительнее
  • Идиомы Compose делают код предсказуемым, тестируемым и производительным

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также