Splash screen animada no Flutter (e FlutterFlow)
Por equipe Charmotion · Atualizado em

A splash nativa do Flutter, configurada à mão ou com flutter_native_splash, é uma imagem estática sobre uma cor de fundo. Para animá-la, mantenha essa splash, faça a sua primeira rota desenhar a mesma cor e a mesma posição do ícone, toque ali uma intro em Rive ou vídeo e depois navegue adiante. FlutterNativeSplash.preserve() e remove() permitem esconder a splash nativa exatamente quando a intro estiver pronta.
Principais pontos
- O flutter_native_splash gera as launch screens de cada plataforma, que são estáticas; o README dele diz que Lottie ainda não é suportado.
- A animação fica na sua primeira rota, desenhada sobre a mesma cor de fundo da splash nativa.
preserve()mantém a splash nativa; chameremove()quando o arquivo da intro tiver carregado.- Uma
LaunchStateMachinedo Charmotion não dispara nenhum evento de fim, então espere 2,6 s antes de navegar. - A configuração de splash do FlutterFlow é uma imagem estática com duração mínima; coloque um widget RiveAnimation na página inicial.
Já tem um personagem ou logo? Veja seu personagem em telas reais de app: telas de splash, onboarding, carregamento e estado vazio. É grátis, roda no navegador e não envia nada.
O flutter_native_splash pode ser animado?
Não no mobile. O pacote gera as launch screens nativas para iOS e Android a partir das suas configurações (uma cor, uma imagem, opções do Android 12 como image e icon_background_color), e essas telas mostram uma imagem estática enquanto a engine do Flutter inicia. O README informa que GIFs agora são suportados na web e que Lotties ainda não são suportados (pub.dev).
Essa não é uma limitação do pacote que dê para contornar. No iOS, a launch screen só pode usar views padrão do UIKit, sem código. No Android, apenas um AnimatedVectorDrawable pode ser animado na splash do sistema, no Android 12 ou posterior (veja o guia do ícone de splash no Android). Em nenhum dos casos o Flutter já está rodando.
Então o padrão é o mesmo dos apps nativos: uma splash estática e, em seguida, uma primeira rota animada que fica idêntica a ela no primeiro frame.
Como criar uma primeira rota animada no Flutter?
Segure a splash nativa, carregue a intro, remova a splash assim que a intro puder ser desenhada, espere a duração da intro e então substitua a rota. Este exemplo usa a API atual do pacote rive (Rive):
import 'package:flutter/material.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:rive/rive.dart';
const bg = Color(0xFF0E1116); // same color as the native splash
Future<void> main() async {
final binding = WidgetsFlutterBinding.ensureInitialized();
FlutterNativeSplash.preserve(widgetsBinding: binding);
await RiveNative.init();
runApp(const MaterialApp(home: IntroPage()));
}
class IntroPage extends StatefulWidget {
const IntroPage({super.key});
@override
State<IntroPage> createState() => _IntroPageState();
}
class _IntroPageState extends State<IntroPage> {
File? file;
RiveWidgetController? controller;
@override
void initState() {
super.initState();
_run();
}
Future<void> _run() async {
final reduce = WidgetsBinding
.instance.platformDispatcher.accessibilityFeatures.disableAnimations;
if (!reduce) {
file = await File.asset('assets/launch.riv', riveFactory: Factory.rive);
if (file != null && mounted) {
setState(() => controller = RiveWidgetController(
file!,
stateMachineSelector: StateMachineSelector.byName('LaunchStateMachine'),
));
}
}
FlutterNativeSplash.remove();
// LaunchStateMachine fires no end event: wait for the 2.6 s intro.
if (controller != null) await Future.delayed(const Duration(milliseconds: 2600));
if (mounted) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (_) => const HomePage()),
);
}
}
@override
void dispose() {
controller?.dispose();
file?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final still = MediaQuery.disableAnimationsOf(context) || controller == null;
return ColoredBox(
color: bg,
child: Center(
child: SizedBox(
width: 160,
height: 160,
child: still
? Image.asset('assets/icon_rest.png')
: RiveWidget(controller: controller!, fit: Fit.contain),
),
),
);
}
}
HomePage representa a sua primeira tela real. MediaQuery.disableAnimationsOf reflete a configuração de movimento reduzido da plataforma (Flutter API); a mesma flag é lida em _run por meio de accessibilityFeatures, porque ainda não existe context em initState.
Dá para usar uma intro em vídeo no Flutter?
Sim. Com video_player (pub.dev), crie o controller a partir de um asset, chame initialize(), remova a splash nativa no callback then e dê play. Escute o controller e navegue quando position chegar a duration.
final video = VideoPlayerController.asset('assets/launch.mp4');
await video.initialize();
FlutterNativeSplash.remove();
video.addListener(() {
final v = video.value;
if (v.isInitialized && v.position >= v.duration) _goHome();
});
await video.setVolume(0);
await video.play();
A intro em vídeo mais simples é um clipe opaco cujo fundo é exatamente a cor da sua splash, exibido em tela cheia ou centralizado sobre essa cor. Se o ícone precisar ficar sobre um gradiente ou uma foto, um .riv com fundo transparente é mais fácil de posicionar no Flutter do que um vídeo. Vídeo funciona bem para ícones 3D ou raster detalhados, mas não consegue reagir a estados depois.
Como fazer uma transição perfeita da splash para a intro?
- Mesma cor. Use a
colordo flutter_native_splash (ecolor_dark, se você oferece modo escuro) como fundo da intro. - Mesmo ícone, mesmo lugar. Use o primeiro frame da intro, ou o ícone em repouso, como imagem da splash, no tamanho em que a intro o desenha. No Android 12+, o ícone da splash é recortado em círculo, então teste se o ícone recortado continua igual.
- Remova a splash só quando estiver pronto. Chame
FlutterNativeSplash.remove()depois que o arquivo da intro carregar, para que o usuário nunca veja um frame vazio. - Não faça o usuário esperar à toa. Cerca de um segundo é o limite para não interromper a linha de raciocínio do usuário (NN/g). Toque uma intro longa só na primeira abertura e, depois, uma curta ou nenhuma.
- Respeite o movimento reduzido. Mostre o ícone estático e siga em frente na hora.
Como adicionar uma splash animada no FlutterFlow?
As configurações de splash do FlutterFlow, em App Assets, aceitam uma imagem enviada com opções de ajuste e tamanho, uma Min Duration em milissegundos, uma Background Color e uma Pre-loading Color para a tela em branco exibida enquanto a engine carrega (FlutterFlow Docs). A documentação não descreve nenhuma opção de animação ali, então trate essa tela como a parte estática.
- Defina a imagem da splash como o seu ícone em repouso e as duas cores como o fundo da sua marca.
- Mantenha a Min Duration curta; ela atrasa todas as aberturas.
- Crie uma página de intro como página inicial, com o mesmo fundo, e coloque um widget RiveAnimation com o seu arquivo de abertura (FlutterFlow Docs).
- No carregamento da página, espere 2,6 s (para um arquivo de abertura do Charmotion) e navegue para a sua página inicial sem transição.
O guia de Rive no FlutterFlow explica os nomes de state machine e o código personalizado, caso você precise de mais controle. O Charmotion exporta o .riv com LaunchStateMachine, além de MP4 e vídeo com fundo transparente, a partir de uma única imagem do seu ícone ou mascote.
Como adicionar uma splash screen animada no Flutter
- Configure uma splash estática. Use o flutter_native_splash com a cor da sua marca e o ícone em repouso.
- Mantenha a splash. Chame
FlutterNativeSplash.preserve(widgetsBinding: binding)emmain(). - Crie a rota da intro. Faça a primeira rota desenhar a mesma cor, com um
RiveWidgetou vídeo no tamanho e na posição do ícone da splash. - Remova e espere. Chame
FlutterNativeSplash.remove()assim que o arquivo carregar, espere a duração da intro (2,6 s para um arquivo de abertura do Charmotion) e depois usepushReplacementpara ir à home. - Trate o movimento reduzido. Se
disableAnimationsestiver ativo, mostre o ícone estático e siga em frente imediatamente.
Perguntas frequentes
O flutter_native_splash consegue tocar uma animação Lottie?
Não. O README diz que Lotties ainda não são suportados, e o suporte a GIF vale só para a web. No iOS e no Android, a splash nativa é uma imagem estática, então toque a animação Lottie, Rive ou em vídeo na sua primeira rota, sobre a mesma cor de fundo.
No Flutter, a intro deve ser uma rota ou um overlay?
Uma rota é o mais simples: uma IntroPage substituída pela página inicial com pushReplacement. Um overlay sobre a página inicial funciona se você quiser que o app seja construído por baixo durante a intro, mas aí garanta que o overlay ignore o input só enquanto estiver visível.
Preciso de uma splash separada para o Android 12 no Flutter?
O flutter_native_splash tem opções para o Android 12 porque, nessa versão, a splash do sistema recorta o ícone em círculo e pode usar uma cor de fundo para o ícone. Forneça uma imagem que continue legível depois do recorte; caso contrário, o pacote usa o ícone do launcher.
Fontes
- flutter_native_splash, pub.dev
- Flutter runtime, Rive
- MediaQuery.disableAnimationsOf, Flutter API
- video_player, pub.dev
- App Assets (splash screen settings), FlutterFlow Docs
- RiveAnimation widget, FlutterFlow Docs
- Response Times: The 3 Important Limits, Nielsen Norman Group
Guias relacionados
- Como adicionar animação a um app Flutter
- Rive e Lottie no FlutterFlow: widgets e limites
- Lottie vs Rive no React Native e no Flutter (2026)
- Guia de animação de abertura e splash screen para apps
- Lottie vs Rive vs vídeo para animação de splash screen
- Prompts de IA para adicionar uma splash screen ou um mascote de carregamento animado