---
title: "Splash Screen API no Android 16 com Kotlin e Jetpack Compose | Kotlin Brasil"
url: "https://kotlin.dev.br/blog/splash-screen-android-16-kotlin-2026/"
markdown_url: "https://kotlin.dev.br/blog/splash-screen-android-16-kotlin-2026.MD"
description: "Implemente a Splash Screen API do Android 16 com Kotlin e Jetpack Compose: duration, ícone, tema windowBackground, animação, Compose e migração do splash legado em 2026."
date: "2026-06-21"
author: "Karina Melo"
---

# Splash Screen API no Android 16 com Kotlin e Jetpack Compose | Kotlin Brasil

Implemente a Splash Screen API do Android 16 com Kotlin e Jetpack Compose: duration, ícone, tema windowBackground, animação, Compose e migração do splash legado em 2026.


A Splash Screen API chegou para padronizar uma das partes mais inconsistentes do Android histórico: a primeira tela do app. Durante anos, todo projeto resolvia o "tempo de inicialização" de um jeito diferente — uma `Activity` em branco com um logo, um `Handler.postDelayed`, às vezes uma biblioteca third-party — e o resultado era duplicação de cold start, animações truncadas e UX inconsistente entre fabricantes. A partir do Android 12 a plataforma passou a controlar o splash nativamente, e em 2026, com o **Android 16** consolidando o `SplashScreen` da AndroidX Core como padrão, manter um splash legado virou dívida técnica com custo real.

Neste guia você implementa a **Splash Screen API no Android 16 com Kotlin e Jetpack Compose**, do zero à migração de um projeto existente, cobrindo duration, ícone adaptativo, `windowBackground`, animação de saída e testes. Se você está começando um app novo, vale revisar antes o [tutorial de criação do primeiro app Android](/tutoriais/primeiro-app-android/) e o [guia de Jetpack Compose](/guias/guia-jetpack-compose/), porque a integração do splash depende da configuração de tema e da raiz de navegação em Compose.

## 1. Por que não fazer um splash "na mão"

A tentação de criar uma `SplashActivity` dedicada ainda existe, mas o custo é alto e quase sempre invisível até virar bug:

- **Cold start duplicado**: a `Activity` extra inflaciona layout, cria `Application`-level DI, roda `setContent` e só então navega para a tela real. O usuário espera o custo de duas telas para ver uma.
- **Quebra em modo gelado / AOT**: em primeiro launch após instalar ou atualizar, o Android já mostra o splash do sistema por cima do seu splash manual, gerando dois logotipos piscando.
- **Comportamento inconsistente entre OEMs**: Samsung, Xiaomi e Pixel renderizam `windowBackground` de formas diferentes; a Splash Screen API normaliza isso.
- **Animação de saída não suportada**: o splash manual não tem hook de "deixe a plataforma animar a transição para o seu primeiro frame Compose".
- **Acessibilidade**: a API nativa respeita contraste, dimensão mínima do ícone e tempo máximo de exibição, coisas fáceis de errar numa implementação caseira.

A regra em 2026 é simples: **deixe a plataforma desenhar o splash, use a AndroidX só para customizar**.

## 2. Dependências

No `libs.versions.toml` (padrão que vale seguir — veja o [guia de Gradle Version Catalog](/blog/gradle-version-catalog-kotlin-2026/)):

```toml
[versions]
androidxCoreSplashscreen = "1.0.1"

[libraries]
androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidxCoreSplashscreen" }
```

No `app/build.gradle.kts`:

```kotlin
dependencies {
    implementation(libs.androidx.core.splashscreen)
}
```

A versão `1.0.1` é estável em 2026 e cobre API 21+ com backport do comportamento do Android 12. Em API 31+ o sistema desenha nativamente; em API mais baixa, a AndroidX simula o mesmo contrato a partir do tema.

## 3. O tema `Theme.SplashScreen`

O ponto central é um tema dedicado que herda de `Theme.SplashScreen`. Em `res/values/themes.xml`:

```xml
<style name="Theme.App.Starting" parent="Theme.SplashScreen">
    <item name="windowSplashScreenBackground">@color/splash_background</item>
    <item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
    <item name="windowSplashScreenAnimationDuration">200</item>
    <item name="postSplashScreenTheme">@style/Theme.App</item>
</style>
```

Pontos críticos que erram em revisão de código:

- **`postSplashScreenTheme` é obrigatório**. Sem ele o app inteiro herda o tema de splash, quebrando Cores, `ColorScheme` do Compose Material 3 e tokens de `windowBackground`.
- **`windowSplashScreenAnimatedIcon` aceita drawable vetorial ou adaptative icon**. Ícones raster estouram em telas high-DPI e não animam.
- **A duração máxima útil é ~1000ms**. Acima disso o sistema corta e o app parece travado. Para uma discussão mais ampla de performance de inicialização, o [guia de performance em Kotlin](/guias/guia-kotlin-performance/) cobre reduzir tempo de cold start além do splash.
- **O ícone tem área de mascaramento**. Use um `vector drawable` com 108dp onde o conteúdo visível fica num círculo de ~72dp centralizado; o sistema pode recortar as bordas.

No `AndroidManifest.xml`:

```xml
<application
    android:name=".App"
    android:theme="@style/Theme.App.Starting">
    <activity
        android:name=".MainActivity"
        android:exported="true"
        android:theme="@style/Theme.App.Starting">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>
```

## 4. Instalar o splash na Activity

A chamada precisa acontecer **antes de `super.onCreate`** e **antes de `setContent`**. É a parte mais fácil de errar:

```kotlin
class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        val splash = installSplashScreen()
        super.onCreate(savedInstanceState)

        var contentReady = mutableStateOf(false)
        splash.setKeepOnScreenCondition { !contentReady.value }

        enableEdgeToEdge()

        setContent {
            AppRoot(contentReady = contentReady)
        }
    }
}
```

O `setKeepOnScreenCondition` é o substituto moderno do "segure o splash enquanto carrega dados". Enquanto retornar `true`, o sistema mantém o splash visível; ao virar `false`, ele anima a saída e entrega o primeiro frame Compose. Esse padrão combina bem com [edge-to-edge no Android 16](/blog/android-16-edge-to-edge-compose-kotlin-2026/), que agora é default.

Importante: **não bloqueie a main thread dentro de `setKeepOnScreenCondition`**. O callback roda no frame loop; carregamento real deve rodar em `LaunchedEffect`, `viewModelScope` ou `Application.onCreate`. Se você precisa inicializar DI, logging ou analytics antes da UI, mova para `Application` ou use um [Startup Provider da AndroidX](/blog/baseline-profiles-macrobenchmark-android-kotlin-2026/).

## 5. Animação de saída customizada

O splash padrão já faz fade-out, mas você pode adicionar uma animação de saída mais marcada com `setOnExitAnimationListener`:

```kotlin
splash.setOnExitAnimationListener { splashView ->
    val iconView = splashView.iconView ?: run {
        splashView.remove()
        return@setOnExitAnimationListener
    }

    val scale = ObjectAnimator.ofFloat(
        iconView, View.SCALE_X, 1f, 0.6f
    ).apply { duration = 150 }

    val alpha = ObjectAnimator.ofFloat(
        splashView.view, View.ALPHA, 1f, 0f
    ).apply { duration = 150 }

    AnimatorSet().apply {
        playTogether(scale, alpha)
        doOnEnd { splashView.remove() }
        start()
    }
}
```

Duas armadilhas:

1. **Sempre chame `splashView.remove()`** no fim. Esquecer isso segura o splash para sempre e vira ANR em produção.
2. **Não exceda ~300ms de animação de saída**. O usuário já esperou o cold start; alongar a transição causa sensação de lentidão.

## 6. Splash no Android 16 especificamente

O Android 16 reforça duas coisas que vale revisar em apps em produção:

- **`enableEdgeToEdge()` é default**, então o tema `Theme.App.Starting` precisa considerar `windowLayoutInDisplayCutoutMode` e `statusBarColor` transparentes, senão o splash mostra borda colorida que some abruptamente na UI real.
- **Modo gelado pré-aquecido**: o sistema pode mostrar o splash antes mesmo do processo do app subir, com o ícone em silhueta. Use um ícone com contraste forte contra `windowSplashScreenBackground` para evitar um "fantasma" ilegível.
- **Suporte a tela inicial preenchida em tablets/dobráveis**: o splash centraliza o ícone em qualquer tamanho de tela; layouts manuais costumam quebrar em `res/values-sw600dp`.

Para apps que ainda têm `windowBackground` customizado, remova-o do tema base e migre para `Theme.SplashScreen` herdando o comportamento de fundo — isso evita flashes de cor diferente entre splash e UI.

## 7. Migração do splash legado

O caminho padrão para um app que ainda usa `SplashActivity`:

1. Remova a `Activity` legada e o filtro de `LAUNCHER` dela.
2. Torne a `MainActivity` real a exportada com `MAIN`/`LAUNCHER`.
3. Aplique `Theme.App.Starting` na `MainActivity` e no `<application>`.
4. Chame `installSplashScreen()` antes de `super.onCreate`.
5. Mova qualquer `Handler.postDelayed` / `Thread.sleep` para `setKeepOnScreenCondition` controlado por estado real (carregamento de feature flags, sessão, etc.).
6. Apague layouts, drawables e bibliotecas de splash third-party.
7. Rode o app em API 21, 31 e o emulador Android 16 para validar consistência.

Esse fluxo costuma reduzir o cold start percebido em 150–300ms e elimina uma classe inteira de bugs de OEM. Se você mantém [Feature Flags](/blog/feature-flags-kotlin-android-backend-2026/) no projeto, vale gatear a migração por flag para poder reverter rápido em caso de regressão visual.

## 8. Como medir o tempo de splash

O tempo percebido de splash não é o que você acha — é o que o usuário vê. Para medir corretamente:

- Use `adb shell am start -W com.seu.app/.MainActivity` e observe `WaitTime` e `TotalTime`.
- Em instrumentação, capture `ActivityManager.ProcessState` ao redor do primeiro frame Compose; o delta entre `installSplashScreen()` e o primeiro frame estável é o tempo real de splash.
- Em produção, registre um evento `app_first_frame` com duração desde `Application.onCreate`; agregue por versão de Android e modelo de dispositivo.

Não confie em cronômetro na mão. Dispositivos com thermal throttle, primeiro launch após OTA ou apps pesados em DI mostram tempos bem diferentes do dev machine.

## 9. Erros comuns em revisão de código

- Esquecer `postSplashScreenTheme` e quebrar o tema do app inteiro.
- Chamar `installSplashScreen()` depois de `setContent` — vira no-op silencioso.
- Manter `windowDisablePreview` no tema, que desativa o splash do sistema.
- Usar `windowSplashScreenAnimatedIcon` com bitmap grande em vez de vector — estoura DPI e consome memória no cold start.
- Animar saída sem chamar `splashView.remove()`.
- Pedir permissão de rede ou I/O dentro do callback `setKeepOnScreenCondition`.

## 10. Quando NÃO usar splash

A Splash Screen API é para **tempo de inicialização frio inevitável**, não para "dar uma sensação de carregamento". Se o seu app abre em menos de 300ms e você está segurando o splash artificialmente, está piorando a UX — remova-o e deixe a plataforma mostrar o mínimo necessário. Para carregamento de dados pesado, prefira skeleton screens na própria UI Compose; o [tutorial de Jetpack Compose](/tutoriais/jetpack-compose-basico/) cobre estados de loading com `Crossfade` e `AnimatedContent`.

## Conclusão

A Splash Screen API no Android 16 é o caminho correto para qualquer app Kotlin em 2026: padroniza o cold start, respeita OEMs, suporta animação de saída e se integra limpo com Compose e edge-to-edge. A migração de um splash legado é pequena (um tema, uma linha em `onCreate`, um callback de condição), mas remove uma fonte permanente de bugs visuais e reduz o tempo percebido de inicialização. A regra é deixar a plataforma desenhar o splash e só customizar o que agrega UX real — ícone da marca, cor de fundo, animação de saída curta. Para o resto, gaste energia em baixar o cold start de verdade, que é onde a melhoria de UX acontece.
