Aula 17 - Jetpack Compose Avançado e Design System Mobile 📱
Objetivo Pedagógico
Objetivo: Projetar interfaces declarativas de alta performance com Jetpack Compose: gerenciamento de recomposição, estado unidirecional (UDF), Custom Layouts, animações de transição e criação de um Design System corporativo coeso.
📑 1. Fundamentos Teóricos & Análise Técnica
O desenvolvimento de interfaces gráficas para Android passou por uma revolução com o abandono do paradigma imperativo baseado em Views XML em favor do Jetpack Compose, um toolkit declarativo e reativo nativo.
O domínio avançado do Compose exige a compreensão profunda do seu compilador e runtime: 1. O Modelo Mental da Recomposição: - Uma função @Composable é transformada pelo plugin do compilador do Kotlin em uma árvore de nós em memória. - Recomposição Inteligente: O runtime do Compose rastreia quais estados foram lidos durante a execução de cada função composable. Quando um estado sofre mutação, apenas os composables que leem diretamente aquele estado são reexecutados. Composables cujos parâmetros não sofreram alteração são ignorados (Skipping). - Estabilidade de Tipos (@Stable e @Immutable): Se uma classe possui propriedades mutáveis sem garantia de notificação, o compilador a marca como instável, desabilitando o skipping e forçando recomposições desnecessárias que afetam a taxa de quadros (60/120 FPS). 2. Unidirectional Data Flow (UDF): - Os eventos fluem exclusivamente para cima (Events Up), disparados pelas interações do usuário nos composables em direção ao ViewModel. - O estado consolidado flui exclusivamente para baixo (State Down), imutável e centralizado, eliminando condições de corrida na UI. 3. Design System Corporativo com Material 3: - Estruturação de tokens de design: paleta tonal dinâmica baseada no wallpaper do usuário (Dynamic Color do Monet engine), tipografia fluida com escala de tipos e tokens semânticos de elevação e espaçamento.
📐 Arquitetura Conceitual & Diagrama de Fluxo
graph TD
User["Interação do Usuário (Click / Input)"] -->|Event Up| VM["ViewModel (UDF Controller)"]
VM -->|Mutação de Estado| State["StateFlow<UiState> (Imutável)"]
State -->|State Down| Screen["Composable Screen (Root)"]
Screen -->|Passa Sub-estados| CompA["Componente Recomponível A (Recompõe)"]
Screen -->|Parâmetros Inalterados| CompB["Componente Recomponível B (SKIPPED!)"]
style User fill:#e1f5fe,stroke:#01579b
style VM fill:#fff3e0,stroke:#e65100
style State fill:#f3e5f5,stroke:#7b1fa2
style CompA fill:#e8f5e9,stroke:#2e7d32
style CompB fill:#eeeeee,stroke:#9e9e9e 🔍 Pilares e Diretrizes Técnicas
Nesta unidade, aprofundamos os seguintes conceitos fundamentais: - Estabilidade e Smart Recomposition: Uso de anotações @Immutable em Data Classes e tipagem estável para maximizar o skipping de funções composable. - Elevação de Estado (State Hoisting): Padrão arquitetural que move o estado para o chamador da função para tornar os componentes reutilizáveis e fáceis de testar. - Subcomposition e Layout Customizado: Criação de componentes com medição sob demanda (MeasurePolicy) para posicionamentos geométricos complexos. - Side-Effects Gerenciados: Controle rigoroso de efeitos colaterais com LaunchedEffect, rememberCoroutineScope e DisposableEffect.
🛠️ 2. Implementação Prática em Android Moderno com Jetpack Compose
Abaixo está a implementação técnica de referência, estruturada com padrões de engenharia de software e foco em robustez:
// DesignSystemComponents.kt (Design System com Tokens Material 3 e Estado Estável)
package com.portal.android.designsystem
import androidx.compose.animation.animateColorAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Immutable
data class OrderCardUiState(
val id: String,
val title: String,
val amountFormatted: String,
val isPriority: Boolean
)
@Composable
fun OrderStatusCard(
state: OrderCardUiState,
onCardClicked: (String) -> Unit,
modifier: Modifier = Modifier
) {
val backgroundColor by animateColorAsState(
targetValue = if (state.isPriority) MaterialTheme.colorScheme.errorContainer
else MaterialTheme.colorScheme.surfaceVariant,
label = "CardBackgroundColorAnimation"
)
Card(
onClick = { onCardClicked(state.id) },
shape = RoundedCornerShape(16.dp),
modifier = modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp)
.background(backgroundColor, RoundedCornerShape(16.dp))
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = state.title,
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurface
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = state.amountFormatted,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.primary
)
}
}
}
💡 Análise Passo a Passo do Código
- Anotação
@Immutable: Informa explicitamente ao compilador do Compose que os campos não mudam após instanciação, permitindo skipping seguro. - Transição Animada de Cores: Utiliza
animateColorAsStatepara transições visuais fluidas a 60 FPS sem travamentos na thread principal. - State Hoisting no Callback: O componente não conhece o ViewModel; apenas emite o evento
onCardClickedpara o chamador superior.
🎯 3. Próximos Passos & Sequência Didática
-
Slides da Aula
-
Quiz de Fixação
-
Exercícios Práticos
-
Desafio de Projeto