Composable Function — este unitatea fundamentală a interfeței de utilizator în Jetpack Compose, care definește cum ar trebui să arate și să se comporte o parte a ecranului. Fiecare astfel de funcție este marcată cu adnotarea @Composable și se execută într-un context special, permițând Compose să urmărească dependențele și să reconstruiască automat UI la modificarea datelor. Conform Google Android Developers, 2026, construirea corectă a funcțiilor Composable influențează direct performanța aplicației și eficiența recompunerii.
Principalele
Composable Function — este o funcție în limbajul Kotlin marcată cu adnotarea @Composable, care descrie o parte a interfeței de utilizator într-un mod declarativ. În loc să creeze și să configureze obiecte View prin cod Java sau XML, dezvoltatorul scrie pur și simplu cum ar trebui să arate UI pentru fiecare stare a datelor.
Diferența principală dintre funcția Composable și sistemul tradițional View din Android constă în modelul de actualizare. În abordarea clasică, dezvoltatorul apela manual findViewById, modifica textul prin setText, gestiona vizibilitatea prin setVisibility. Composable Function eliberează de această rutină: la modificarea datelor, sistemul determină singur care funcții trebuie repornite și execută doar pe acestea.
Compilatorul Kotlin, procesând adnotarea @Composable, generează cod suplimentar care integrează funcția în mecanismul de compunere. Acest cod include citirea și scrierea în sloturi — celule de memorie speciale care stochează starea și parametrii fiecărei funcții Composable în arborele UI curent. Datorită acestei integrări, Compose știe care funcții depind de care date.
Sintaxa funcției Composable este cât se poate de concisă: este suficient să adăugați @Composable înainte de cuvântul cheie fun. Funcția poate accepta orice parametri, poate include alte apeluri Composable în corpul său și poate folosi construcții Kotlin — condiții, bucle, expresii when — pentru afișarea condiționată a 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("Adaugă în coș")
}
}
}
}
În acest exemplu, funcția Composable ProductItem acceptă un obiect Product, un modificator și un callback. Toți cei trei parametri sunt imutabili, ceea ce garantează un comportament previzibil la recompunere. Modificatorul este transmis ca parametru cu o valoare implicită — aceasta este o practică standard care permite părții apelante să personalizeze spațiile și dimensiunile.
În interiorul funcției Composable se folosesc componente încorporate Material Design (Text, Button, Card, TextField) sau primitive fundamentale (Canvas, Layout). Fiecare componentă acceptă parametri pentru configurarea aspectului și comportamentului, precum și unul sau mai mulți modificatori prin parametrul modifier.
Modificatorii (Modifier) — sunt un lanț de funcții care modifică dimensiunea, poziția, gestionarea evenimentelor și aspectul componentei. Ordinea modificatorilor în lanț contează: clickable.semantics funcționează diferit de semantics.clickable, iar padding.background colorează fundalul zonei inclusiv paddingul, ceea ce este critic în proiectare.
În interiorul funcției Composable se pot folosi condiții if și when pentru afișarea condiționată a părților UI, precum și bucle for pentru liste dinamice. Toate aceste construcții funcționează natural, deoarece Kotlin este un limbaj de programare complet. Este important de reținut: dacă condiția sau bucla conține apeluri ale funcțiilor Composable, acestea participă și ele la recompunere.
@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 */ }
)
}
}
}
Să analizăm un exemplu de ecran de căutare a produselor folosind mai multe funcții Composable. Aici sunt prezentate modele tipice: câmp de introducere cu stare, filtrarea listei, gestionarea rezultatului gol și a încărcării.
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("Caută produse") },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
when (products) {
is Loading -> CircularProgressIndicator()
is Empty -> Text("Niciun rezultat găsit")
is Result -> LazyColumn {
items(products.items, key = { it.id }) { product ->
ProductItem(product = product, onAddToCart = {})
}
}
}
}
}
Acest exemplu demonstrează simultan mai multe idiomuri: remember pentru salvarea stării interogării de căutare, remember(query) pentru filtrarea cu cheie, when pentru trei stări ale UI și LazyColumn pentru afișarea eficientă a listei. Fiecare dintre aceste idiomuri este rezultatul experienței practice în dezvoltarea aplicațiilor Compose.
Funcțiile Composable acceptă parametri la fel ca funcțiile obișnuite Kotlin, dar cu o diferență importantă: parametrul poate fi o altă funcție Composable transmisă printr-o lambda cu adnotarea @Composable. Acest mecanism se numește Slot API și este modelul principal pentru crearea containerelor reutilizabile.
Slot API rezolvă problema care în sistemul tradițional View era rezolvată prin ViewGroup și adăugarea programatică a View-urilor copil. În locul metodelor addView, Compose folosește lambda-uri content — ultimul parametru cu tipul @Composable () -> Unit. Partea apelantă transmite în această lambda orice UI, iar containerul însuși determină doar amplasarea acestuia.
Parametrii funcției Composable pot avea valori implicite, ceea ce simplifică utilizarea lor în contexte diferite. Se recomandă să faceți obligatorii doar acei parametri fără de care funcția nu își poate îndeplini sarcina, iar pe ceilalți să îi dotați cu valori implicite rezonabile.
| Parametru | Tip | Exemplu |
|---|---|---|
| Obligatoriu | Orice tip | name: String |
| Opțional | Cu valoare implicită | modifier: Modifier = Modifier |
| Content | @Composable () -> Unit | content: @Composable () -> Unit |
| Callback | Lambda fără @Composable | onClick: () -> Unit |
În comunitatea Compose s-au format câteva idiomuri consacrate care fac funcțiile Composable mai lizibile și mai previzibile. Primul — State Hoisting: starea este ridicată la un nivel superior, iar funcția Composable o primește prin parametri. Acest lucru face funcția pură și reutilizabilă în contexte diferite.
Al doilea idiom — parametri Event-driven. În loc să transmitem ViewModel sau useCase în funcția Composable, se transmit doar callback-uri specifice: onSave, onDelete, onNavigateToDetail. Aceasta reduce cuplarea și simplifică testarea — pentru testul ProductItem nu este nevoie de ViewModel, ci doar de un lambda-stub.
Al treilea idiom — CompositionLocal pentru transmiterea datelor comune prin arborele de compunere. Tema, densitatea ecranului, ruta curentă — toate acestea se transmit prin CompositionLocal, evitând lanțuri de parametri prin zeci de funcții Composable. Cu toate acestea, nu trebuie abuzat de CompositionLocal: parametrii explicitați sunt întotdeauna preferabili dependențelor implicite.
// State Hoisting: stare ridicată la funcția părinte
@Composable
fun CounterDisplay(
count: Int,
onIncrement: () -> Unit
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "Contor: $count", style = MaterialTheme.typography.headlineLarge)
Button(onClick = onIncrement) {
Text("+1")
}
}
}
// Utilizare cu State Hoisting
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }
CounterDisplay(
count = count,
onIncrement = { count++ }
)
}
Întrebări frecvente
Da, return este permis, dar cu prudență. Compose optimizează recompunerea la nivelul funcțiilor individuale, iar o returnare timpurie poate perturba această optimizare. Este mai bine să folosiți operatori condiționali if sau when în interiorul corpului funcției.
În Kotlin, Unit este un obiect singleton, nu un tip gol. Funcțiile Composable returnează Unit, ceea ce înseamnă tehnic că returnează însuși obiectul Unit. Cu toate acestea, în practică nu contează — valoarea returnată este ignorată de sistemul de compunere.
Transmiterea colecțiilor mutabile este posibilă, dar este o practică proastă. Dacă colecția se modifică, Compose nu va afla despre aceasta, deoarece referința la obiect rămâne aceeași. Folosiți liste imutabile sau mutableStateListOf pentru modificări urmăribile.
Pentru depanare, folosiți Android Studio cu Layout Inspector, care arată arborele curent al funcțiilor Composable, valorile parametrilor și motivele recompunerii. Funcționează și debugger-ul obișnuit Kotlin — punctele de întrerupere din interiorul funcțiilor Composable se declanșează corect la fiecare recompunere.
Funcția Composable returnează întotdeauna Unit, prin urmare return type nu se specifică. Încercarea de a returna un alt tip va cauza o eroare de compilare, deoarece adnotarea @Composable este incompatibilă cu tipurile de returnare diferite de Unit.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și