---
title: "Animações no Jetpack Compose: Guia Prático em 2026 | Kotlin Brasil"
url: "https://kotlin.dev.br/blog/animacoes-jetpack-compose-kotlin-2026/"
markdown_url: "https://kotlin.dev.br/blog/animacoes-jetpack-compose-kotlin-2026.MD"
description: "Aprenda a criar animações no Jetpack Compose em 2026 com Kotlin: animate*AsState, AnimatedVisibility, AnimatedContent, updateTransition, animações infinitas, Modifier.animateItem, specs e performance."
date: "2026-07-10"
author: "Karina Melo"
---

# Animações no Jetpack Compose: Guia Prático em 2026 | Kotlin Brasil

Aprenda a criar animações no Jetpack Compose em 2026 com Kotlin: animate*AsState, AnimatedVisibility, AnimatedContent, updateTransition, animações infinitas, Modifier.animateItem, specs e performance.


Animação boa é aquela que o usuário não percebe — ele só sente que o app é fluido, rápido e "caro". No Jetpack Compose, diferente do antigo sistema de Views, animar não é mais uma tarefa de quem desenha nem uma parafernália de `ObjectAnimator` e XML. Animação virou uma consequência natural de mudar de **estado**: você descreve o que quer mostrar para cada estado e o Compose calcula os quadros intermediários para você.

Este guia mostra como criar **animações no Jetpack Compose em 2026**, do botão que muda de cor até listas que reordenam com fluidez, passando por transições de tela, loaders e animações imperativas. Se você ainda está consolidando a base, vale revisar antes o [guia de Jetpack Compose](/guias/guia-jetpack-compose/) e o tutorial de [Jetpack Compose básico](/tutoriais/jetpack-compose-basico/), porque este texto pressupõe que você já entende [composables](/glossario/composable/), [modifiers](/glossario/modifier/) e [state](/glossario/state/).

## Resposta rápida: qual API usar?

Antes de mergulhar, use este mapa mental para escolher a ferramenta certa. A maioria dos casos cai em um destes cinco grupos:

| Situação | API recomendada |
|---|---|
| Animar um valor único (cor, tamanho, opacidade) | `animate*AsState` |
| Mostrar ou esconder um elemento | `AnimatedVisibility` |
| Trocar conteúdo entre estados distintos | `AnimatedContent` ou `Crossfade` |
| Coordenar várias propriedades numa mesma mudança | `updateTransition` |
| Animação que roda para sempre (loader, pulse) | `rememberInfiniteTransition` |

A regra prática: comece pela API mais simples do topo da tabela. Se ela não resolver, desça uma linha. Quase nunca você precisa de animações manuais com `Animatable`.

## Dependências

As APIs de animação vêm no artefato `androidx.compose.animation`, que já entra automaticamente quando você usa o Compose BOM. Em um projeto criado pelo Android Studio em 2026, o `libs.versions.toml` costuma trazer algo como:

```toml
[versions]
composeBom = "2026.07.00"

[libraries]
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
compose-animation = { group = "androidx.compose.animation", name = "animation" }
compose-foundation = { group = "androidx.compose.foundation", name = "foundation" }
```

```kotlin
dependencies {
    implementation(platform(libs.compose.bom))
    implementation(libs.compose.animation)
    implementation(libs.compose.foundation)
}
```

O `Modifier.animateContentSize()` e o `Modifier.animateItem()` moram no `foundation`; o resto (`AnimatedVisibility`, `AnimatedContent`, `updateTransition`) vem do `animation`. Não há nada extra para configurar.

## 1. `animate*AsState`: o canivete suíço

Quando um valor muda de estado e você quer que ele chegue ao novo valor de forma suave, use `animate*AsState`. Existem variantes para `Color`, `Dp`, `Float`, `Int`, `Size`, `Offset`, `Rect` e `Value` genérico.

```kotlin
var selecionado by remember { mutableStateOf(false) }

val corDeFundo by animateColorAsState(
    targetValue = if (selecionado) Color(0xFF6650A4) else Color.LightGray,
    animationSpec = spring(dampingRatio = Spring.DampingRatioMediumBouncy),
    label = "corDeFundo"
)

Button(
    onClick = { selecionado = !selecionado },
    colors = ButtonDefaults.buttonColors(containerColor = corDeFundo)
) {
    Text("Selecionar")
}
```

Note o detalhe que confunde iniciantes: o `animate*AsState` retorna um `State`, por isso usamos `by` (delegação) e não `=`. Esquecer o `by` compila, mas a animação nunca acontece, porque você passa a função em vez do valor animado.

O parâmetro `label` é **obrigatório em 2026** para qualquer função `animate*` e `updateTransition`. Ele aparece no Layout Inspector e nos relatórios de recomposição, e ajuda muito a depurar animações travadas.

## 2. `AnimatedVisibility`: entra e sai com elegância

Para elementos que aparecem e desaparecem, `AnimatedVisibility` cuida das transições de entrada (`enter`) e saída (`exit`) com composables prontos:

```kotlin
var expandido by remember { mutableStateOf(false) }

Column {
    TextButton(onClick = { expandido = !expandido }) {
        Text(if (expandido) "Recolher" else "Expandir")
    }
    AnimatedVisibility(
        visible = expandido,
        enter = fadeIn(animationSpec = tween(300)) +
                expandVertically(),
        exit = fadeOut(animationSpec = tween(200)) +
               shrinkVertically()
    ) {
        Card(Modifier.fillMaxWidth().padding(top = 8.dp)) {
            Text(
                "Conteúdo que só faz sentido quando expandido.",
                Modifier.padding(16.dp)
            )
        }
    }
}
```

O operador `+` combina transições — você pode somar um `fadeIn` com um `slideInVertically`, por exemplo. Isso é o equivalente moderno de encadear vários `Animator` no sistema de Views, mas sem o boilerplate.

## 3. `AnimatedContent` e `Crossfade`: trocar de estado

Quando o conteúdo muda com base num estado (um contador, uma aba, um passo de wizard), `AnimatedContent` faz a transição entre o conteúdo antigo e o novo. `Crossfade` é a versão simples, só com fade cruzado.

```kotlin
var passo by remember { mutableIntStateOf(1) }

AnimatedContent(
    targetState = passo,
    transitionSpec = {
        (slideInHorizontally { width -> width } + fadeIn() togetherWith
         slideOutHorizontally { width -> -width } + fadeOut())
    },
    label = "passoWizard"
) { passoAtual ->
    Text("Passo $passoAtual", Modifier.padding(24.dp))
}
```

Dica importante: a transição é definida no `transitionSpec`, que recebe `AnimatedContentTransitionScope` como receptor. Use `togetherWith` para ligar o `enter` ao `exit`. O lambda final (`{ passoAtual -> ... }`) desenha o conteúdo de cada estado — é nele que você consome o valor.

## 4. `updateTransition`: coordenar várias animações

Quando uma única mudança de estado dispara várias propriedades ao mesmo tempo (cor, tamanho, elevação), `updateTransition` mantém tudo sincronizado:

```kotlin
enum class EstadoCard { Repousando, Pressionado }

@Composable
fun CardInterativo() {
    var estado by remember { mutableStateOf(EstadoCard.Repousando) }
    val transicao = updateTransition(targetState = estado, label = "card")

    val escala by transicao.animateFloat(label = "escala") { estado ->
        when (estado) {
            EstadoCard.Repousando -> 1f
            EstadoCard.Pressionado -> 0.96f
        }
    }
    val elevacao by transicao.animateDp(label = "elevacao") { estado ->
        when (estado) {
            EstadoCard.Repousando -> 2.dp
            EstadoCard.Pressionado -> 8.dp
        }
    }

    Card(
        Modifier
            .graphicsLayer { scaleX = escala; scaleY = escala }
            .pointerInput(Unit) {
                detectTapGestures(
                    onPress = {
                        estado = EstadoCard.Pressionado
                        tryAwaitRelease()
                        estado = EstadoCard.Repousando
                    }
                )
            }
    ) {
        Text("Toque em mim", Modifier.padding(20.dp))
    }
}
```

A vantagem sobre vários `animate*AsState` isolados é que todas as propriedades partem do mesmo `targetState` no mesmo instante, então não há dessincronização visual. Para cards, chips e botões com feedback de toque, é a escolha certa.

## 5. `rememberInfiniteTransition`: loaders e pulsos

Animações que rodam para sempre — loaders, indicadores de pulsação, esqueletos de carregamento — usam `rememberInfiniteTransition` com a spec `infiniteRepeatable`:

```kotlin
@Composable
fun CoracaoBatendo(modifier: Modifier = Modifier) {
    val transicao = rememberInfiniteTransition(label = "batimento")
    val escala by transicao.animateFloat(
        initialValue = 1f,
        targetValue = 1.15f,
        animationSpec = infiniteRepeatable(
            animation = tween(700, easing = FastOutSlowInEasing),
            repeatMode = RepeatMode.Reverse
        ),
        label = "escalaBatimento"
    )

    Icon(
        Icons.Filled.Favorite,
        contentDescription = "Favoritado",
        modifier = modifier.scale(escala),
        tint = Color.Red
    )
}
```

`RepeatMode.Reverse` vai e volta (efeito pulso); `RepeatMode.Restart` reinicia do início a cada ciclo (típico de spinners). Evite usar isso em elementos que ficam sempre visíveis na tela de fundo, porque a animação roda a 60 ou 120 quadros por segundo o tempo todo e consome bateria.

## 6. `Animatable`: controle imperativo

Quando você precisa orquestrar uma sequência (animar até um ponto, esperar, animar de novo) ou integrar com [coroutines](/glossario/coroutine/), use `Animatable`. Ele suspende dentro de um `LaunchedEffect`:

```kotlin
@Composable
fun BarraDeProgressoAnimada(modifier: Modifier = Modifier) {
    val progresso = remember { Animatable(0f) }

    LaunchedEffect(Unit) {
        progresso.animateTo(0.7f, animationSpec = tween(1200))
        delay(300)
        progresso.animateTo(1f, animationSpec = tween(600))
    }

    LinearProgressIndicator(
        progress = { progresso.value },
        modifier = modifier.fillMaxWidth()
    )
}
```

`Animatable` é thread-safe (vive no composition, mas só uma coroutine anima por vez) e é a base sobre a qual as outras APIs são construídas.

## 7. Modifiers que animam sozinhos

Dois modifiers resolvem problemas comuns sem código extra:

- **`Modifier.animateContentSize()`** — quando o tamanho de um composable muda (por exemplo, um texto que expande), ele interpola a transição em vez de pular de tamanho.
- **`Modifier.animateItem()`** — dentro de `LazyColumn` e `LazyRow`, anima inserções, remoções e reordenação de itens. Em 2026 ele **substitui o antigo `animateItemPlacement()`**, que está deprecado.

```kotlin
LazyColumn {
    items(tarefas, key = { it.id }) { tarefa ->
        Row(
            Modifier
                .fillMaxWidth()
                .animateItem()
                .padding(12.dp)
        ) {
            Text(tarefa.titulo)
        }
    }
}
```

A `key` é indispensável aqui: sem ela, o Compose recria os itens em vez de animá-los, e o efeito some.

## Specs: controlando tempo e curva

Todas as APIs aceitam um `animationSpec`. Os mais usados:

- **`spring()`** — física real (mola), o padrão do Compose. Ajuste `dampingRatio` para mais ou menos "salto" e `stiffness` para velocidade.
- **`tween(durationMillis, easing)`** — duração fixa com uma curva de easing. Use para tempos previsíveis.
- **`keyframes()`** — define valores em instantes específicos, ideal para coreografias.
- **`snap()`** — sem interpolação, pula direto para o valor.

Prefira `spring` para interações de toque (ele reage à velocidade do dedo) e `tween` com `FastOutSlowInEasing` para transições de tela.

## Performance: não brigue com a recomposição

Animações lentas quase sempre vêm de recomposição excessiva, não da API em si. Três hábitos mantêm tudo a 60fps:

1. **Anime valores, não composables.** Mudar `scale` via `Modifier.graphicsLayer` recompõe menos do que trocar o `Modifier.size`. Quanto menos o composable recompor, mais fluido.
2. **Derive de estado estável.** Use `remember` e `derivedStateOf` para evitar recalcular specs a cada frame.
3. **Confira no Layout Inspector.** A aba "Animations" e o contador de recomposição mostram exatamente qual composable está pegando fogo.

Para testar se a animação continua correta após refatorar, vale o [artigo sobre testes de screenshot no Compose](/blog/testes-screenshot-compose-kotlin-2026/), que captura regressões visuais na CI.

## Casos de uso reais

- **Carrinho de compra em app de delivery**: use `AnimatedVisibility` para revelar a barra flutuante de "finalizar pedido" quando há itens, e `Modifier.animateItem()` para a lista de produtos.
- **Onboarding em fintake**: `AnimatedContent` entre os passos do tutorial, com `slideInHorizontally` para dar sensação de avanço.
- **Botão de favoritar**: `updateTransition` coordenando ícone, cor e escala no mesmo toque.
- **Tela de carregamento**: `rememberInfiniteTransition` em um logo que pulsa enquanto a chamada de rede não retorna.

Esses padrões cobrem a maioria dos apps Android que você encontra no mercado brasileiro, de marketplaces a apps de banco.

## Perguntas frequentes

**Preciso da biblioteca Lottie para animar no Compose?** Não para a maioria dos casos. As APIs nativas cobrem transições, estados e microinterações. Lottie faz sentido para animações complexas feitas por designers no After Effects, que não dá para reproduzir declarativamente.

**Qual a diferença entre `AnimatedContent` e `Crossfade`?** `Crossfade` só faz o fade cruzado entre os estados. `AnimatedContent` permite definir `transitionSpec` customizado (slide, scale, expansão), sendo muito mais flexível.

**`animateItemPlacement` ainda funciona?** Funciona com aviso de depreciação. Em projetos novos use `Modifier.animateItem()`, que é a API unificada e recomendada a partir do Compose Foundation 1.7.

**Animações gastam muita bateria?** Animações reativas a estado (que só rodam durante a interação) têm custo desprezível. O problema é `rememberInfiniteTransition` rodando em segundo plano — pause-o quando o elemento sair da tela.

## Conclusão

O jeito Compose de animar troca a pergunta: em vez de "como eu animo isso?", você pergunta "qual é o estado?". A animação sai de graça quando você descreve a UI como função do estado. Comece com `animate*AsState`, escale para `updateTransition` quando precisar coordenar propriedades e guarde `Animatable` para sequências imperativas.

Para ir além, combine o que você aprendeu aqui com [Material 3 Expressive](/blog/material-3-expressive-compose-kotlin-2026/), que traz tokens de motion baseados em `Spring` e transições compartilhadas com `SharedTransitionLayout`, e ative o [Compose Hot Reload](/blog/compose-hot-reload-kotlin-2026/) para iterar nas animações sem recompilar o app inteiro a cada ajuste.
