Анотација @Composable — основни елемент Jetpack Compose који претвара обичну Kotlin функцију у декларативни блок за изградњу корисничког интерфејса. Без ове анотације није могуће креирати ниједан екран у савременом Android развоју. Према Google Android Developers, 2026, преко 80% нових пројеката у Kotlin-у користи Compose за изградњу UI, а @Composable је најчешће коришћена анотација у екосистему.
Главно
@Composable — је анотација језика Kotlin која означава функцију као намењену за описивање корисничког интерфејса у оквиру Jetpack Compose. Када Kotlin компилер наиђе ову анотацију, генерише додатан код који омогућава функцији да ради у контексту композиције — систему за управљање UI дрветом.
Анотација @Composable је представљена од стране Google-а 2021. године заједно са првом стабилном верзијом Jetpack Compose 1.0. Пре њеног појављивања, развој интерфејса за Android се одвијао искључиво кроз XML ознаке и View систем. @Composable је коренито променила приступ: уместо описивања UI-а у засебном фајлу за ознаке, програмер пише интерфејс директно у Kotlin-у.
Главна разлика између @Composable и обичних Kotlin функција — способност да чита и реагује на промене стања. Када промењива коју Composable функција чита промени вредност, систем аутоматски планира поновно покретање (рекомпозицију) те функције. Ово ослобађа програмера од ручног ажурирања UI кроз findViewById и setText.
Унутрашња механика @Composable се ослања на концепт слота — посебне меморијске области која се додељује свакој функцији у саставу композиције. У овом слоту чувају се вредности прослеђене функцији, као и помоћне информације потребне за поређење при каснијим позивима.
За декларисање Composable функције довољно је додати анотацију @Composable пре кључне речи fun. Функција мора да се налази у пакету који увози анотацију из androidx.compose.runtime. Назив функције се препоручује да се пише великим почетним словом — ово је општеприхваћена конвенција у Compose заједници која визуелно одваја UI компоненте од обичних функција.
import androidx.compose.runtime.Composable
@Composable
fun Greeting(name: String) {
var count by remember { mutableStateOf(0) }
Column {
Text("Здраво, $name!")
Button(onClick = { count++ }) {
Text("Кликнуто $count пута")
}
}
}
Параметри Composable функције могу бити било какви — примитивни типови, низке, ламбде и чак друге Composable функције које се преносе кроз Slot API. Препоручује се да параметри буду непромењиви (val) да би се избегли нуспоредни ефекти при рекомпозицији. Сви промењиви подаци треба да се управљају кроз Compose механизме стања.
Composable функције не могу враћати произвољну вредност као обичне функције — њихов једини задатак је да изграде или ажурирају део UI дрвета. Ипак, постоје посебни обрасци као што је State Hoisting, у коме Compose функција прима стање и callback-е кроз параметре, остајући чиста и поновно употребљива.
Compose систем намеће неколико строгих ограничења на то како Composable функције треба да изгледају и понашају се. Прво правило: Composable функција може позивати само друге Composable функције или обичне функције без нуспоредних ефеката. Ово осигурава предвидљивост композиције и исправан рад Compose оптимизација.
Друго правило се односи на редослед извршавања. Compose има право да позива Composable функције у било којем редоследу, па код у телу такве функције не треба да зависи од редоследа позивања суседних функција. Свака Composable функција треба да буде самодовољна на нивоу своје позиције у UI дрвету.
Треће правило — забрана нуспоредних ефеката у самом телу Composable функције. Операције као што су упис у базу података, слање мрежних захтева или промена спољашњих промењивих морају се извршавати само унутар посебних ефеката LaunchedEffect, DisposableEffect или SideEffect. Кршење овог правила доводи до непредвидљивог понашања при рекомпозицијама.
Четврто правило: Composable функције морају бити идемпотентне. Поновни позив са истим аргументима треба да произведе исти UI. Овај захтев је потребан за исправан рад skipping оптимизације, при којој Compose прескаче прецртавање функција чији се улазни подаци нису промењени.
// Исправно: чиста Composable функција без нуспоредних ефеката
@Composable
fun UserCard(user: User, onClick: () -> Unit) {
Card(modifier = Modifier.clickable { onClick() }) {
Text(text = user.name)
}
}
// Неисправно: нуспоредни ефекат у телу
@Composable
fun WrongCard(userId: String) {
// val result = viewModel.loadUser(userId) // НИЈЕ ДОЗВОЉЕНО
Text("Учитавање...")
}
Размотримо практичан пример креирања екрана профила коришћећем @Composable анотације. Овде демонстрирамо комбиновање више Composable функција, рад са стањем и модификаторима — кључним елементима сваког Compose распореда.
@Composable
fun ProfileScreen(userId: String) {
var isFollowed by remember { mutableStateOf(false) }
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
ProfileHeader(userId = userId)
Spacer(modifier = Modifier.height(16.dp))
StatsRow(posts = 42, followers = 1280)
Spacer(modifier = Modifier.height(24.dp))
FollowButton(
isFollowed = isFollowed,
onToggle = { isFollowed = !isFollowed }
)
}
}
@Composable
fun ProfileHeader(userId: String) {
Row(verticalAlignment = Alignment.CenterVertically) {
AsyncImage(model = "https://example.com/avatars/$userId",
contentDescription = "User avatar")
Spacer(modifier = Modifier.width(12.dp))
Text(text = "Корисник #$userId", style = MaterialTheme.typography.headlineMedium)
}
}
@Composable
fun StatsRow(posts: Int, followers: Int) {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
StatItem("Posts", posts)
StatItem("Followers", followers)
}
}
@Composable
fun StatItem(label: String, value: Int) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "$value", style = MaterialTheme.typography.headlineSmall)
Text(text = label, style = MaterialTheme.typography.bodySmall)
}
}
У примеру, свака Composable функција је одговорна за свој део екрана: ProfileScreen управља општим стањем и композицијом потомака, ProfileHeader приказује аватар и име, а StatsRow — блок са статистиком. Овакав приступ прати принцип јединствене одговорности и поједностављује поновну употребу компонената.
У Jetpack Compose-у постоје три главне врсте Composable функција. Прва врста — контејнери (Row, Column, Box, LazyColumn) који одређују положај потомака. Друга — елементи приказа (Text, Image, Icon, Button) који рендерују одређене UI компоненте. Трећа — прилагођене Composable функције које комбинују уграђене компоненте у поновно употребљиве блокове.
Контејнери се разликују од обичних елемената по томе што прихватају content ламбду — последњи параметар типа @Composable () -> Unit. Управо овај механизам омогућава изградњу угнеждених UI дрвата: сваки појединачни контејнер ствара потомачку композицију са сопственим контекстом и меморијском облашчу.
Прилагођене Composable функције се деле на два подтипа: паметне (smart) и глупе (dumb). Паметне функције управљају стањем и логиком — садрже позиве remember, LaunchedEffect и других Compose API-ја. Глупе функције примају све податке кроз параметре и само их приказују. Подела на паметне и глупе компоненте побољшава тестирање и поновну употребу кода.
| Врста | Пример | Намена |
|---|---|---|
| Контејнер | Column, Row, Box | Управљање положајем потомака |
| Елемент | Text, Image, Button | Приказ садржаја и обрада уноса |
| Прилагођени | ProfileCard, UserList | Комбинација стандардних компонената |
Главна предност @Composable анотације — могућност креирања поновно употребљивих UI компонената без наслеђивања и сложених хијерархија класа. За разлику од View система, где је сваки прилагођени елеменат захтевао креирање Java класе са конструкторима, Composable компонента је једноставно Kotlin функција са параметрима.
За обезбеђеђе поновне употребе примењује се образац Slot API, при коме Composable функција прихвата content ламбде за различите области свог распореда. На пример, Card компонента може да прима одвојен content за наслов, тело и доњи део, што га чини универзалним за било које екране апликације.
Модификатори (Modifier) играју кључну улогу у поновном коришћењу: омогућавају подешавање размака, величина, кликова и анимација без измене самог компонента. Препоручује се да увек преносите Modifier као параметар Composable функције са подразумеваном вредношчу: Modifier = Modifier — ово је стандардна пракса усвојена у званичним Google библиотекама.
@Composable
fun SectionCard(
modifier: Modifier = Modifier,
title: String,
content: @Composable () -> Unit
) {
Card(modifier = modifier) {
Column(modifier = Modifier.padding(16.dp)) {
Text(text = title, style = MaterialTheme.typography.titleMedium)
Spacer(modifier = Modifier.height(8.dp))
content()
}
}
}
Захваљујући Slot API-у, SectionCard компонента се може користити на различитим екранима са различитим садржајем — формуларима, списковима, текстуалним блоковима. Комбиновање модификатора и Slot API-а чини Compose компоненте максимално флексибилним без губитка типске сигурности коју обезбеђује Kotlin.
Често постављана питања
@Composable функција се извршава у контексту композиције и може да чита стање, аутоматски се поново покрећући при његовој промени. Обичне Kotlin функције немају приступ механизмима праћења стања и не учествују у изградњи UI дрвета.
Не, Composable функције се могу позивати само из других Composable функција, јер је потребан посебан контекст композиције. За интеграцију Compose кода са обичним Kotlin-ом користи се метода setContent { } у Activity или ComposeView у View систему.
То је конвенција именовања усвојена у Compose заједници. Велико почетно слово визуелно одваја UI компоненте од обичних функција, пратећи правила именовања класа. Ово није захтев компилера, већ препоручена пракса у Google документацији.
Нема ограничења у броју. У пракси, велики екран може да садржи 50–100 Composable функција, укључујући уграђене компоненте (Text, Button) и прилагођене. Compose оптимизује дрво функција и извршава само оне чији су се улазни подаци променили.
Обично Composable функције враћају Unit, јер је њихов задатак да изграде UI. Ипак, постоје специјализоване функције као што су remember и derivedStateOf које су означене са @Composable и враћају вредности. То је изузетак, а не правило.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође