Jetpack Compose é o toolkit moderno do Google para construir interfaces nativas no Android usando Kotlin. Em vez de manipular Views com XML, você descreve sua UI de forma declarativa com funções Composable. Neste tutorial, vamos explorar os fundamentos do Jetpack Compose e entender como ele revoluciona o desenvolvimento de interfaces Android. Se você está começando com Android ou migrando de XML, este guia vai apresentar tudo o que precisa saber.
O que é Programação Declarativa de UI?
No paradigma imperativo tradicional do Android (XML + Views), você define a UI em arquivos XML e depois manipula cada componente programaticamente, alterando propriedades e respondendo a eventos. Isso frequentemente resulta em código verboso e propenso a bugs, pois você precisa manter a UI sincronizada manualmente com o estado da aplicação.
Com o Jetpack Compose, você adota o paradigma declarativo: em vez de dizer ao framework como atualizar a UI, você declara como ela deve parecer para cada estado. Quando o estado muda, o Compose automaticamente recompõe (recomposes) apenas os componentes afetados, garantindo que a UI sempre reflita o estado atual.
Uma função Composable é marcada com a annotation @Composable e descreve um pedaço da interface. Composables podem chamar outros Composables, formando uma árvore de componentes.
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@Composable
fun Saudacao(nome: String) {
Text(text = "Olá, $nome! Bem-vindo ao Kotlin Brasil.")
}
@Composable
fun TelaPrincipal() {
Saudacao(nome = "Maria")
}
No exemplo acima, Saudacao é um Composable que recebe um parâmetro nome e exibe um texto formatado. O TelaPrincipal compõe a tela chamando Saudacao com um nome específico. Essa composição de funções é o coração do Jetpack Compose.
Gerenciamento de Estado com remember e mutableStateOf
O estado é fundamental no Jetpack Compose. Quando um valor de estado muda, o Compose recompõe automaticamente todos os Composables que leem esse valor. Para criar e gerenciar estado dentro de um Composable, usamos remember e mutableStateOf.
O remember preserva o valor entre recomposições, enquanto mutableStateOf cria um estado observável que dispara recomposição quando modificado.
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun Contador() {
var contagem by remember { mutableStateOf(0) }
Column(
modifier = Modifier
.fillMaxSize()
.padding(32.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "Contagem: $contagem",
style = MaterialTheme.typography.headlineLarge
)
Spacer(modifier = Modifier.height(16.dp))
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Button(onClick = { contagem++ }) {
Text("Incrementar")
}
OutlinedButton(onClick = { contagem-- }) {
Text("Decrementar")
}
TextButton(onClick = { contagem = 0 }) {
Text("Resetar")
}
}
}
}
Neste exemplo, contagem é um estado local do Composable Contador. Cada vez que o usuário clica em um dos botões, o valor é atualizado e o Compose recompõe apenas os componentes que dependem de contagem, neste caso, o Text que exibe o número.
O by é um operador de Delegação de propriedades em Kotlin. Ele delega o getter e setter da variável contagem ao MutableState<Int> retornado por mutableStateOf(0). Isso permite acessar e modificar o valor diretamente, sem precisar chamar .value explicitamente.
É importante entender que remember só preserva o estado durante a vida do Composable na composição. Se o Composable for removido e adicionado novamente, ou se houver uma mudança de configuração (como rotação de tela), o estado será perdido. Para estado que precisa sobreviver a essas situações, use rememberSaveable ou ViewModel.
Composables do Material Design 3
O Jetpack Compose inclui uma biblioteca completa de componentes Material Design 3, que oferece botões, campos de texto, cards, diálogos e muito mais, todos prontos para uso e personalizáveis.
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Share
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CartaoExemplo() {
var expandido by remember { mutableStateOf(false) }
Card(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Aprendendo Jetpack Compose",
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = if (expandido) {
"Jetpack Compose é o toolkit moderno para UI no Android. " +
"Ele simplifica o desenvolvimento de interfaces com código " +
"declarativo e reativo, eliminando a necessidade de XML."
} else {
"Jetpack Compose é o toolkit moderno para UI no Android..."
},
style = MaterialTheme.typography.bodyMedium
)
Spacer(modifier = Modifier.height(12.dp))
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
IconButton(onClick = { /* ação de favoritar */ }) {
Icon(Icons.Default.Favorite, contentDescription = "Favoritar")
}
IconButton(onClick = { /* ação de compartilhar */ }) {
Icon(Icons.Default.Share, contentDescription = "Compartilhar")
}
Spacer(modifier = Modifier.weight(1f))
TextButton(onClick = { expandido = !expandido }) {
Text(if (expandido) "Ver menos" else "Ver mais")
}
}
}
}
}
Os componentes do Material Design 3 seguem as diretrizes de design do Google e suportam temas dinâmicos (Dynamic Color) no Android 12+. Você pode personalizar cores, tipografia e formas através do MaterialTheme, que define o estilo visual de toda a aplicação.
A anotação @OptIn(ExperimentalMaterial3Api::class) é necessária para usar APIs que ainda estão em fase experimental. Isso é comum em componentes mais recentes do Material Design 3.
Modifiers: Estilizando e Posicionando Composables
Os Modifiers são a forma principal de estilizar e posicionar Composables no Jetpack Compose. Eles permitem definir tamanho, padding, margem, cor de fundo, borda, eventos de clique e muito mais. Os Modifiers são encadeados e a ordem importa.
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
@Composable
fun ExemploModifiers() {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.shadow(8.dp, RoundedCornerShape(12.dp))
.clip(RoundedCornerShape(12.dp))
.background(MaterialTheme.colorScheme.surface)
.border(1.dp, Color.LightGray, RoundedCornerShape(12.dp))
.clickable { /* ação ao clicar */ }
.padding(24.dp),
contentAlignment = Alignment.Center
) {
Text(
text = "Modifiers são poderosos!",
style = MaterialTheme.typography.titleMedium
)
}
}
A ordem dos Modifiers é crucial. No exemplo acima, o padding(16.dp) externo é aplicado antes do shadow e background, criando margem ao redor do Box. O padding(24.dp) interno é aplicado depois do background, criando espaço dentro do Box. Trocar a ordem dos Modifiers resulta em aparências completamente diferentes.
Os Modifiers mais usados incluem fillMaxWidth(), fillMaxHeight(), fillMaxSize(), size(), padding(), background(), clickable(), clip() e weight() (dentro de Row/Column).
Dicas e Erros Comuns
Não usar
remember: semremember, o estado é recriado a cada recomposição, resultando em componentes que parecem não responder a interações. Sempre envolvamutableStateOfcomremember.Composables pesados dentro de LazyColumn: evite fazer operações pesadas (cálculos, formatações complexas) diretamente dentro de itens de
LazyColumn. Pré-calcule os valores ou userememberpara cachear resultados.Ignorar a ordem dos Modifiers: a ordem dos Modifiers afeta o resultado visual.
paddingantes debackgroundcria margem;paddingdepois debackgroundcria espaço interno. Experimente trocar a ordem para entender o comportamento.Não usar
derivedStateOf: quando um estado depende de outro (ex: filtrar uma lista baseado em um texto de busca), usederivedStateOfpara evitar recomposições desnecessárias.Esquecer
contentDescriptionem ícones: para acessibilidade, sempre forneça uma descrição para ícones e imagens. Isso permite que leitores de tela descrevam o conteúdo para usuários com deficiência visual.
Conclusão e Próximos Passos
Neste tutorial, você aprendeu os fundamentos do Jetpack Compose: funções Composable, gerenciamento de estado com remember e mutableStateOf, componentes Material Design 3 e o sistema de Modifiers. Esses conceitos formam a base para construir qualquer interface Android moderna.
O Jetpack Compose é o futuro do desenvolvimento de UI no Android, e dominá-lo é essencial para qualquer desenvolvedor Kotlin. A abordagem declarativa simplifica o código, reduz bugs relacionados ao estado e torna o desenvolvimento mais produtivo.
Para continuar sua jornada com Jetpack Compose, recomendamos:
- Layouts com Jetpack Compose para dominar Row, Column, Box e layouts avançados
- Primeiro App Android com Kotlin para aplicar Compose em um projeto completo
- Coroutines Avançadas: Flow e Channel para integrar Flow com Compose
- Delegação de Propriedades para entender melhor o
byusado comremember