Composable Function é uma unidade fundamental da interface do usuário no Jetpack Compose que define como uma parte da tela deve parecer e se comportar. Cada uma dessas funções é marcada com a anotação @Composable e executada em um contexto especial que permite ao Compose rastrear dependências e reconstruir automaticamente a UI quando os dados mudam. De acordo com Google Android Developers, 2026, a construção adequada de funções Composable afeta diretamente o desempenho do aplicativo e a eficiência da recomposição.
Pontos principais
Uma Composable Function é uma função na linguagem Kotlin, marcada com a anotação @Composable, que descreve uma parte da interface do usuário de forma declarativa. Em vez de criar e configurar objetos View através de código Java ou marcação XML, o desenvolvedor simplesmente escreve como a UI deve parecer para cada estado dos dados.
A principal diferença entre uma função Composable e o sistema tradicional de View do Android está no modelo de atualização. Na abordagem clássica, o desenvolvedor chamava manualmente findViewById, alterava o texto via setText e gerenciava a visibilidade via setVisibility. Composable Function liberta-o desta rotina: quando os dados mudam, o próprio sistema determina quais funções precisam ser recompostas e executa apenas essas.
O compilador Kotlin, ao processar a anotação @Composable, gera código adicional que integra a função no mecanismo de composição. Este código inclui leitura e escrita em slots — células de memória especiais que armazenam o estado e os parâmetros de cada função Composable na árvore de UI atual. Graças a esta integração, o Compose sabe quais funções dependem de quais dados.
A sintaxe de uma função Composable é extremamente concisa: basta adicionar @Composable antes da palavra-chave fun. A função pode aceitar qualquer parâmetro, incluir outras chamadas Composable no seu corpo e usar construções Kotlin — condições, loops, expressões when — para renderização condicional da 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("Adicionar ao carrinho")
}
}
}
}
Neste exemplo, a função Composable ProductItem aceita um objeto Product, um modificador e um callback. Os três parâmetros são imutáveis, o que garante um comportamento previsível durante a recomposição. O modificador é passado como parâmetro com um valor padrão — esta é uma prática padrão que permite a quem chama personalizar padding e tamanhos.
Dentro de uma função Composable, são utilizados componentes integrados do Material Design (Text, Button, Card, TextField) ou primitivas fundamentais (Canvas, Layout). Cada componente aceita parâmetros para configurar aparência e comportamento, bem como um ou mais modificadores através do parâmetro modifier.
Os modificadores são uma cadeia de funções que alteram o tamanho, posição, manipulação de eventos e aparência de um componente. A ordem dos modificadores na cadeia importa: clickable.semantics funciona de forma diferente de semantics.clickable, e padding.background pinta tanto a área como o fundo incluindo o padding, o que é crítico ao projetar.
Dentro de uma função Composable, pode usar condições if e when para renderização condicional de partes da UI, bem como loops for para listas dinâmicas. Todas estas construções funcionam naturalmente porque Kotlin é uma linguagem de programação completa. No entanto, é importante lembrar: se uma condição ou loop contiver chamadas a funções Composable, elas também participam na recomposição.
@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 */ }
)
}
}
}
Vamos considerar um exemplo de um ecrã de pesquisa de produtos usando várias funções Composable. Padrões típicos são mostrados aqui: um campo de entrada com estado, filtragem de lista, tratamento de resultados vazios e carregamento.
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("Pesquisar produtos") },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
when (products) {
is Loading -> CircularProgressIndicator()
is Empty -> Text("Nenhum resultado encontrado")
is Result -> LazyColumn {
items(products.items, key = { it.id }) { product ->
ProductItem(product = product, onAddToCart = {})
}
}
}
}
}
Este exemplo demonstra vários modismos de uma vez: remember para preservar o estado da consulta de pesquisa, remember(query) para filtrar com uma chave, when para três estados de UI e LazyColumn para renderização eficiente de listas. Cada um destes modismos é o resultado da experiência prática no desenvolvimento de aplicações Compose.
As funções Composable aceitam parâmetros tal como as funções Kotlin normais, mas com uma diferença importante: um parâmetro pode ser outra função Composable passada através de uma lambda com a anotação @Composable. Este mecanismo chama-se Slot API e é o padrão principal para criar contentores reutilizáveis.
O Slot API resolve o problema que no sistema tradicional de View era resolvido através de ViewGroup e adição programática de Views filhas. Em vez de métodos addView, o Compose usa lambdas content — o último parâmetro com o tipo @Composable () -> Unit. Quem chama passa qualquer UI dentro desta lambda, e o contentor apenas define a sua disposição.
Os parâmetros das funções Composable podem ter valores padrão, o que simplifica o seu uso em diferentes contextos. É recomendado tornar obrigatórios apenas os parâmetros sem os quais a função não pode realizar a sua tarefa, e fornecer valores padrão razoáveis para os restantes.
| Parâmetro | Tipo | Exemplo |
|---|---|---|
| Obrigatório | Qualquer tipo | name: String |
| Opcional | Com valor padrão | modifier: Modifier = Modifier |
| Content | @Composable () -> Unit | content: @Composable () -> Unit |
| Callback | Lambda sem @Composable | onClick: () -> Unit |
Na comunidade Compose, vários modismos estabelecidos surgiram que tornam as funções Composable mais legíveis e previsíveis. O primeiro é State Hoisting: o estado é elevado para um nível superior e a função Composable recebe-o através de parâmetros. Isto torna a função pura e reutilizável em diferentes contextos.
O segundo modismo são os parâmetros Event-driven. Em vez de passar uma ViewModel ou useCase para uma função Composable, apenas são passados callbacks específicos: onSave, onDelete, onNavigateToDetail. Isto reduz o acoplamento e simplifica os testes — um teste para ProductItem não precisa de uma ViewModel, apenas de um stub lambda.
O terceiro modismo é CompositionLocal para passar dados partilhados através da árvore de composição. O tema, densidade do ecrã, rota atual — tudo isto é passado através de CompositionLocal, evitando cadeias de parâmetros através de dezenas de funções Composable. No entanto, não se deve abusar do CompositionLocal: parâmetros explícitos são sempre preferíveis a dependências implícitas.
// State Hoisting: estado elevado para a função pai
@Composable
fun CounterDisplay(
count: Int,
onIncrement: () -> Unit
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "Contador: $count", style = MaterialTheme.typography.headlineLarge)
Button(onClick = onIncrement) {
Text("+1")
}
}
}
// Uso com State Hoisting
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }
CounterDisplay(
count = count,
onIncrement = { count++ }
)
}
Perguntas frequentes
Sim, return é permitido, mas com precaução. O Compose otimiza a recomposição ao nível de funções individuais, e um return precoce pode quebrar esta otimização. É melhor usar operadores condicionais if ou within do corpo da função.
Em Kotlin, Unit é um objeto singleton, não um tipo vazio. As funções Composable retornam Unit, o que tecnicamente significa que retornam o próprio objeto Unit. No entanto, na prática isto não importa — o valor de retorno é ignorado pelo sistema de composição.
Passar coleções mutáveis é possível, mas é uma má prática. Se a coleção mudar, o Compose não saberá porque a referência ao objeto permanece a mesma. Use listas imutáveis ou mutableStateListOf para alterações rastreadas.
Para depurar, use Android Studio com Layout Inspector, que mostra a árvore atual de funções Composable, valores dos parâmetros e razões da recomposição. O depurador normal do Kotlin também funciona — os pontos de interrupção dentro de funções Composable são ativados corretamente em cada recomposição.
Uma função Composable retorna sempre Unit, por isso o tipo de retorno não é especificado. Tentar retornar outro tipo causará um erro de compilação porque a anotação @Composable é incompatível com tipos de retorno que não sejam Unit.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também