Composable Function: co to jest, składnia funkcji i zasady

Autor: IT Sectr Opublikowano: 2026-06-27 Czas czytania: 8 min

Composable Function — to fundamentalna jednostka interfejsu użytkownika w Jetpack Compose, która określa, jak powinna wyglądać i zachowywać się część ekranu. Każda taka funkcja jest oznaczona adnotacją @Composable i wykonywana w specjalnym kontekście, umożliwiającym Compose śledzenie zależności i automatyczne przebudowywanie UI przy zmianie danych. Według Google Android Developers, 2026, prawidłowe budowanie Composable-funkcji bezpośrednio wpływa na wydajność aplikacji i efektywność rekompozycji.

Najważniejsze

  • Composable Function — funkcja Kotlin z adnotacją @Composable, budująca drzewo UI
  • Parametry powinny być niemutowalne, a zmienne dane — przez state
  • Wywołanie możliwe tylko z kontekstu innej Composable-funkcji
  • Kolejność wykonania nie jest gwarantowana — każda funkcja powinna być niezależna
  • Modifier zaleca się przekazywać jako parametr do personalizacji

Czym jest Composable Function w Jetpack Compose

Composable Function — to funkcja w języku Kotlin oznaczona adnotacją @Composable, która opisuje część interfejsu użytkownika w sposób deklaratywny. Zamiast tworzyć i konfigurować obiekty View przez kod Java lub XML, programista po prostu pisze, jak UI powinien wyglądać przy każdym stanie danych.

Podstawowa różnica między Composable-funkcją a tradycyjnym systemem View w Androidzie polega na modelu aktualizacji. W klasycznym podejściu programista ręcznie wywoływał findViewById, zmieniał tekst przez setText, zarządzał widocznością przez setVisibility. Composable Function uwalnia od tej rutyny: przy zmianie danych system sam określa, które funkcje należy uruchomić ponownie, i wykonuje tylko je.

Kompilator Kotlin, przetwarzając adnotację @Composable, generuje dodatkowy kod, który integruje funkcję z mechanizmem kompozycji. Ten kod obejmuje odczyt i zapis do slotów — specjalnych komórek pamięci przechowujących stan i parametry każdej Composable-funkcji w bieżącym drzewie UI. Dzięki tej integracji Compose wie, które funkcje zależą od których danych.

Składnia deklaracji Composable-funkcji

Składnia Composable-funkcji jest maksymalnie zwięzła: wystarczy dodać @Composable przed słowem kluczowym fun. Funkcja może przyjmować dowolne parametry, zawierać inne wywołania Composable w swoim ciele i używać konstrukcji Kotlin — warunków, pętli, wyrażeń when — do warunkowego wyświetlania 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("Dodaj do koszyka")
            }
        }
    }
}

W tym przykładzie Composable-funkcja ProductItem przyjmuje obiekt Product, modyfikator i callback. Wszystkie trzy parametry są niemutowalne, co gwarantuje przewidywalne zachowanie przy rekompozycji. Modyfikator jest przekazany jako parametr z domyślną wartością — to standardowa praktyka, pozwalająca stronie wywołującej dostosowywać odstępy i rozmiary.

Komponenty i modyfikatory w Composable-funkcjach

Wewnątrz Composable-funkcji używane są wbudowane komponenty Material Design (Text, Button, Card, TextField) lub fundamentalne prymitywy (Canvas, Layout). Każdy komponent przyjmuje parametry do konfiguracji wyglądu i zachowania, a także jeden lub więcej modyfikatorów przez parametr modifier.

Modyfikatory (Modifier) — to łańcuch funkcji, które zmieniają rozmiar, położenie, obsługę zdarzeń i wygląd komponentu. Kolejność modyfikatorów w łańcuchu ma znaczenie: clickable.semantics działa inaczej niż semantics.clickable, a padding.background koloruje tło obszaru wraz z paddingiem, co jest krytyczne przy projektowaniu.

Wewnątrz Composable-funkcji można używać warunków if i when do warunkowego wyświetlania części UI, a także pętli for do dynamicznych list. Wszystkie te konstrukcje działają naturalnie, ponieważ Kotlin to pełnoprawny język programowania. Należy jednak pamiętać: jeśli warunek lub pętla zawiera wywołania Composable-funkcji, one również uczestniczą w rekompozycji.

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 */ }
            )
        }
    }
}

Przykłady Composable-funkcji dla rzeczywistych ekranów

Rozważmy przykład ekranu wyszukiwania produktów z użyciem kilku Composable-funkcji. Pokazano tutaj typowe wzorce: pole wprowadzania ze stanem, filtrowanie listy, obsługa pustego wyniku i ładowania.

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("Szukaj produktów") },
            modifier = Modifier.fillMaxWidth()
        )

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

        when (products) {
            is Loading -> CircularProgressIndicator()
            is Empty -> Text("Nie znaleziono wyników")
            is Result -> LazyColumn {
                items(products.items, key = { it.id }) { product ->
                    ProductItem(product = product, onAddToCart = {})
                }
            }
        }
    }
}

Ten przykład demonstruje kilka idiomów jednocześnie: remember do przechowywania stanu zapytania, remember(query) do filtrowania z kluczem, when dla trzech stanów UI oraz LazyColumn do efektywnego wyświetlania listy. Każdy z tych idiomów jest wynikiem praktycznego doświadczenia w tworzeniu aplikacji Compose.

Parametry i Slot API

Composable-funkcje przyjmują parametry tak samo jak zwykłe funkcje Kotlin, ale z jedną ważną różnicą: parametr może być inną Composable-funkcją przekazaną przez lambdę z adnotacją @Composable. Ten mechanizm nazywa się Slot API i jest głównym wzorcem do tworzenia wielokrotnego użytku kontenerów.

Slot API rozwiązuje problem, który w tradycyjnym systemie View był rozwiązywany przez ViewGroup i programowe dodawanie dzieci View. Zamiast metod addView Compose używa lambd content — ostatniego parametru z typem @Composable () -> Unit. Strona wywołująca przekazuje do tej lambdy dowolny UI, a sam kontener tylko określa jego rozmieszczenie.

Parametry Composable-funkcji mogą mieć wartości domyślne, co upraszcza ich użycie w różnych kontekstach. Zaleca się czynić obowiązkowymi tylko te parametry, bez których funkcja nie może wykonać swojego zadania, a pozostałe wyposażać w rozsądne wartości domyślne.

ParametrTypPrzykład
ObowiązkowyDowolny typname: String
OpcjonalnyZ wartością domyślnąmodifier: Modifier = Modifier
Content@Composable () -> Unitcontent: @Composable () -> Unit
CallbackLambda bez @ComposableonClick: () -> Unit

Idiomy Composable-funkcji w Kotlin

W społeczności Compose wykształciło się kilka ustalonych idiomów, które czynią Composable-funkcje bardziej czytelnymi i przewidywalnymi. Pierwszy — State Hoisting: stan jest podnoszony na wyższy poziom, a Composable-funkcja otrzymuje go przez parametry. To czyni funkcję czystą i wielokrotnego użytku w różnych kontekstach.

Drugi idiom — Event-driven parametry. Zamiast przekazywać do Composable-funkcji ViewModel lub useCase, przekazywane są tylko konkretne callbacki: onSave, onDelete, onNavigateToDetail. To zmniejsza zależności i upraszcza testowanie — do testu ProductItem nie potrzeba ViewModel, tylko lambda-stub.

Trzeci idiom — CompositionLocal do przekazywania wspólnych danych przez drzewo kompozycji. Motyw, gęstość ekranu, bieżąca trasa — wszystko to jest przekazywane przez CompositionLocal, unikając łańcuchów parametrów przez dziesiątki Composable-funkcji. Nie należy jednak nadużywać CompositionLocal: jawne parametry są zawsze preferowane nad niejawnymi zależnościami.

kotlin
// State Hoisting: stan podniesiony do funkcji nadrzędnej
@Composable
fun CounterDisplay(
    count: Int,
    onIncrement: () -> Unit
) {
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text(text = "Licznik: $count", style = MaterialTheme.typography.headlineLarge)
        Button(onClick = onIncrement) {
            Text("+1")
        }
    }
}

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

Często zadawane pytania

Czy można użyć return w Composable-funkcji?

Tak, return jest dozwolone, ale z ostrożnością. Compose optymalizuje rekompozycję na poziomie poszczególnych funkcji, a wczesny return może zakłócić tę optymalizację. Lepiej używać operatorów warunkowych if lub when wewnątrz ciała funkcji.

Czym różni się Unit-return od void w Javie?

W Kotlin Unit to obiekt-singleton, a nie pusty typ. Composable-funkcje zwracają Unit, co technicznie oznacza, że zwracają sam obiekt Unit. Jednak w praktyce nie ma to znaczenia — zwracana wartość jest ignorowana przez system kompozycji.

Czy można przekazać mutableListOf do Composable-funkcji?

Przekazywanie mutowalnych kolekcji jest możliwe, ale to zła praktyka. Jeśli kolekcja się zmieni, Compose nie dowie się o tym, ponieważ referencja do obiektu pozostała ta sama. Używaj immutable-list lub mutableStateListOf do śledzenia zmian.

Jak debugować Composable-funkcję?

Do debugowania używaj Android Studio z Layout Inspector, który pokazuje bieżące drzewo Composable-funkcji, wartości parametrów i przyczyny rekompozycji. Działa również zwykły debugger Kotlin — punkty przerwania wewnątrz Composable-funkcji poprawnie wyzwalają się przy każdej rekompozycji.

Czy obowiązkowe jest określenie return type w Composable-funkcji?

Composable-funkcja zawsze zwraca Unit, dlatego return type nie jest określany. Próba zwrócenia innego typu spowoduje błąd kompilacji, ponieważ adnotacja @Composable jest niezgodna z typami zwracanymi innymi niż Unit.

Podsumowanie

  • Composable Function — deklaratywny blok budulcowy UI oznaczony @Composable
  • Parametry powinny być niemutowalne dla przewidywalnej rekompozycji
  • Modyfikatory i Slot API zapewniają elastyczność i wielokrotne użycie bez dziedziczenia
  • State Hoisting — wyniesienie stanu na górę dla czystości i testowalności
  • Event-driven callbacki zmniejszają zależności od ViewModel i logiki biznesowej
  • CompositionLocal jest używany dla wspólnych danych, ale jawne parametry są preferowane
  • Idiomy Compose czynią kod przewidywalnym, testowalnym i wydajnym

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również