Splash screen animado en Expo y React Native
Por el equipo de Charmotion · Actualizado el

En Expo, mantén estática la splash screen nativa, llama a SplashScreen.preventAutoHideAsync() al iniciar, renderiza tu intro sobre el mismo color de fondo y llama a hideAsync() cuando la intro esté lista para dibujarse. La intro puede ser un archivo de Rive, un video o Lottie. Rive necesita un development build en lugar de Expo Go, y Expo recomienda revisar el splash en un build de release.
Puntos clave
- El splash de Expo se configura al compilar (color, imagen, ancho, modo oscuro) y solo incluye un fundido integrado.
- Llama a
preventAutoHideAsync()en el ámbito global y luego oculta el splash cuando el primer fotograma de tu intro esté listo. - Usa un solo color hex para el
backgroundColordel splash, la vista raíz y la pantalla de la intro. - Rive y otras librerías de animación nativas necesitan un development build; Expo Go muestra tu ícono en lugar del splash.
- Un archivo de inicio de Charmotion no dispara ningún evento de fin: espera 2.6 s y luego continúa.
¿Ya tienes un personaje o logo? Mira tu personaje en pantallas reales de una app: pantallas de splash, onboarding, carga y estado vacío. Es gratis, funciona en tu navegador y no sube nada.
¿Se puede animar el propio splash screen de Expo?
No. El splash nativo se define con el config plugin expo-splash-screen mediante un backgroundColor, una image, un imageWidth, un resizeMode y una variante dark, y esos ajustes se compilan en el binario (Expo). Por debajo, es la pantalla de inicio de iOS y el splash screen de Android, con los mismos límites.
{
"expo": {
"backgroundColor": "#0E1116",
"plugins": [
["expo-splash-screen", {
"backgroundColor": "#0E1116",
"image": "./assets/icon-rest.png",
"imageWidth": 160,
"dark": { "backgroundColor": "#0E1116", "image": "./assets/icon-rest.png" }
}]
]
}
}
El único movimiento que ofrece Expo es un fundido de salida: SplashScreen.setOptions({ duration, fade }), donde fade solo funciona en iOS y la duración predeterminada es de 400 ms. Cualquier cosa más, como que tu ícono aparezca con un pequeño rebote, tiene que ser un componente de React que renderices justo después del splash, que es lo que hacen los propios ejemplos de splash animado de Expo (Expo Blog).
¿Cómo funcionan preventAutoHideAsync y hideAsync?
preventAutoHideAsync() mantiene visible el splash nativo hasta que llamas a hideAsync() (o hide()). La documentación de Expo indica llamarla en el ámbito global sin await, para que se ejecute antes del primer render. Después, ocúltalo en el momento en que tu intro pueda dibujar su primer fotograma, ni antes ni tras un retraso arbitrario.
// app/_layout.tsx (Expo Router)
import * as SplashScreen from "expo-splash-screen";
import { useState } from "react";
import { Stack } from "expo-router";
import { LaunchIntro } from "../components/LaunchIntro";
SplashScreen.preventAutoHideAsync();
SplashScreen.setOptions({ duration: 200, fade: true });
export default function RootLayout() {
const [showApp, setShowApp] = useState(false);
if (!showApp) return <LaunchIntro onDone={() => setShowApp(true)} />;
return <Stack />;
}
Aquí showApp es tu propio estado de React, no un evento del archivo de animación. El componente de la intro decide cuándo ocultar el splash y cuándo llamar a onDone.
¿Cómo evitar el destello blanco entre el splash y la intro?
Un destello blanco significa que algo de otro color se dibujó entre el splash nativo y tu intro. Elimina cualquier hueco:
- Un solo hex en todas partes. Usa el mismo valor para el
backgroundColordel plugin de splash, elbackgroundColorraíz de la app y el contenedor de la intro. La configuración de la app de Expo describe el color raíz como el fondo "detrás de cualquiera de tus vistas de React" e indica que requiereexpo-system-uien iOS (Expo). - También en modo oscuro. Configura las opciones
darkdel splash y elige el fondo de la intro según el mismo esquema de color. - Oculta en el momento justo. Llama a
hideAsync()cuando el archivo de animación ya se haya cargado, no al montar el componente. Si ocultas antes, verás por un instante un árbol de React vacío. - Misma posición. Renderiza el ícono de la intro centrado y con el
imageWidthdel splash, para que la transición no dé un salto.
El ejemplo de splash con video de Evan Bacon aplica la misma regla con negro: fondos negros en la app, el splash y el splash de iOS, el splash nativo retenido hasta que el video se carga, y luego el video se reproduce y el splash se oculta (GitHub).
¿La intro debería ser Rive, video o Lottie?
| Opción | Ideal para | Ten en cuenta |
|---|---|---|
Rive (@rive-app/react-native) | Un archivo vectorial ligero cuya intro da paso a una mascota de marca interactiva (loading, success, error) | Módulo nativo: requiere development build; la guía de Expo de Rive indica SDK 53+ e iOS 15.1+ |
Video (expo-video) | Intros detalladas, en 3D o ráster; revelaciones a pantalla completa | Archivo más pesado; sin interacción. Lo más sencillo es un clip opaco cuyo fondo coincida con el color del splash |
Lottie (lottie-react-native) | Una animación vectorial lineal que un diseñador ya exportó | Se reproduce de principio a fin; cambiar a otros estados implica intercambiar archivos o segmentos |
Si el mismo personaje debe seguir vivo en la app después del inicio, Rive te ahorra un segundo asset. Si la intro es una cinemática única, el video requiere menos código. En ambos casos, el patrón de transición no cambia. Consulta Lottie vs Rive vs video para un splash screen para la comparación completa y Rive en Expo para configurar el development build.
¿Cómo reproducir una intro de inicio de Rive en Expo?
Este componente retiene el splash nativo hasta que el archivo se carga, reproduce la máquina de estados de inicio, respeta Reducir movimiento y llama a onDone cuando termina la duración de la intro. Usa el runtime actual de Rive para React Native (Rive) y AccessibilityInfo de React Native (React Native).
import { useEffect, useState } from "react";
import { AccessibilityInfo, Image, View } from "react-native";
import * as SplashScreen from "expo-splash-screen";
import { RiveView, useRiveFile } from "@rive-app/react-native";
const BG = "#0E1116"; // same hex as the splash backgroundColor
const INTRO_MS = 2600; // LaunchStateMachine fires no end event
export function LaunchIntro({ onDone }: { onDone: () => void }) {
const { riveFile } = useRiveFile(require("../assets/launch.riv"));
const [reduce, setReduce] = useState<boolean | null>(null);
useEffect(() => {
AccessibilityInfo.isReduceMotionEnabled().then(setReduce);
// Safety net: never trap the user if the file fails to load.
const t = setTimeout(() => { SplashScreen.hideAsync(); onDone(); }, 4000);
return () => clearTimeout(t);
}, []);
useEffect(() => {
if (reduce === null) return;
if (reduce) { SplashScreen.hideAsync(); onDone(); return; }
if (!riveFile) return;
SplashScreen.hideAsync();
const t = setTimeout(onDone, INTRO_MS);
return () => clearTimeout(t);
}, [reduce, riveFile]);
return (
<View style={{ flex: 1, backgroundColor: BG, alignItems: "center", justifyContent: "center" }}>
{riveFile && !reduce ? (
<RiveView file={riveFile} stateMachineName="LaunchStateMachine"
autoPlay={true} style={{ width: 160, height: 160 }} />
) : (
<Image source={require("../assets/icon-rest.png")} style={{ width: 160, height: 160 }} />
)}
</View>
);
}
Registra riv como extensión de asset en metro.config.js para que require funcione, como se explica en Rive en Expo. Para una intro en video, reemplaza la vista de Rive por un reproductor expo-video (Expo) y oculta el splash cuando el reproductor esté listo.
Un set de Charmotion incluye este archivo de inicio: LaunchStateMachine reproduce una vez una intro de 2.6 segundos de tu ícono o mascota y se detiene en la pose de reposo. Charmotion exporta Rive y video, no Lottie.
¿Por qué mi splash no se ve bien en Expo Go o en un dev build?
Porque ninguno es la versión real. La documentación de Expo indica que Expo Go muestra el ícono de tu app en lugar del splash screen, y que los development builds tampoco reflejan del todo los ajustes del config plugin, por lo que recomienda probar el splash en un release build.
- Expo Go: sin splash personalizado y sin Rive, porque el paquete de Rive contiene código nativo (Expo).
- Development build: sirve para construir el componente de la intro, pero no es una vista previa fiel del splash.
- Release o preview build: el único lugar para evaluar la coincidencia de color y el momento de la transición. Prueba un arranque en frío, el modo claro y oscuro, y Reducir movimiento activado.
Después de cambiar los ajustes del splash en app.json, vuelve a compilar la app nativa (npx expo prebuild --clean para builds locales); el splash queda integrado en el binario y no se actualiza con una recarga de JavaScript.
Cómo agregar un splash screen animado en Expo
- Configura un splash estático. Define
backgroundColor,image,imageWidthydarken el pluginexpo-splash-screen, y el mismobackgroundColorraíz. - Retén el splash. Llama a
SplashScreen.preventAutoHideAsync()en el ámbito global de tu layout raíz. - Renderiza la intro. Muestra un componente de intro sobre el mismo fondo, con el ícono al tamaño del splash, usando Rive,
expo-videoo Lottie. - Oculta y espera. Llama a
hideAsync()cuando la intro pueda dibujarse y continúa cuando termine su duración (2.6 s para un archivo de inicio de Charmotion), con un timeout de seguridad. - Prueba un release build. Revisa el arranque en frío, el modo oscuro y Reducir movimiento en un release o preview build, no en Expo Go.
Preguntas frecuentes
¿Puedo usar un GIF como imagen del splash de Expo?
La imagen del splash la muestra la pantalla de inicio nativa, que solo admite una imagen fija. Usa un PNG estático para el splash y reproduce cualquier animación, ya sea un GIF, un video o un archivo de Rive, en la primera pantalla de React con el mismo color de fondo.
¿preventAutoHideAsync funciona en Expo Go?
La función existe, pero Expo Go muestra el ícono de tu app en lugar del splash que configuraste, así que ahí no puedes evaluar la transición. Usa un release build para comprobar cómo se ven juntos tu splash y tu intro.
¿Cómo sé cuándo terminó una intro de inicio de Rive en React Native?
Si el archivo dispara su propio evento, escúchalo. Una LaunchStateMachine de Charmotion no dispara ninguno: reproduce una vez su intro de 2,6 segundos y se detiene en la pose de reposo, así que inicia un temporizador de 2600 ms cuando el archivo se cargue y continúa cuando termine.
Fuentes
- SplashScreen (expo-splash-screen), Expo
- app.json / app.config.js reference (backgroundColor), Expo
- How to add an animated splash screen with Expo Custom Assets, Expo Blog
- expo-splash-video-example, Evan Bacon on GitHub
- Introduction to development builds, Expo
- Adding Rive to Expo, Rive
- React Native runtime, Rive
- AccessibilityInfo, React Native
- Video (expo-video), Expo
Guías relacionadas
- Rive en Expo: requiere un development build (no Expo Go)
- Cómo agregar animación a una app de React Native
- Lottie vs Rive en React Native y Flutter (2026)
- Guía de animaciones de inicio y splash screen para apps
- Lottie vs Rive vs video para animar un splash screen
- Prompts de IA para agregar una mascota animada en el splash o la pantalla de carga