कंटेंट पर जाएँ
charmotion

Expo और React Native में एनिमेटेड स्प्लैश स्क्रीन

Charmotion टीम द्वारा · अपडेट:

गाइड का कवर इलस्ट्रेशन: Expo और React Native में एनिमेटेड स्प्लैश स्क्रीन, Charmotion के डेमो कैरेक्टर के साथ

Expo में, native स्प्लैश स्क्रीन को स्थिर रखें, startup पर SplashScreen.preventAutoHideAsync() call करें, अपना intro उसी बैकग्राउंड कलर पर render करें, और intro के draw होने के लिए तैयार होते ही hideAsync() call करें। intro एक Rive file, वीडियो या Lottie हो सकता है। Rive के लिए Expo Go के बजाय development build चाहिए, और Expo सलाह देता है कि splash को release build में चेक करें।

मुख्य बातें

  • Expo splash build time पर कॉन्फ़िगर होती है (color, image, width, dark mode) और इसमें केवल built-in fade होता है।
  • global scope में preventAutoHideAsync() call करें, फिर जब आपके intro का पहला फ़्रेम तैयार हो, तब splash hide करें।
  • Splash के backgroundColor, root view और intro स्क्रीन, तीनों के लिए एक ही hex color इस्तेमाल करें।
  • Rive और दूसरी native एनिमेशन लाइब्रेरी के लिए development build चाहिए; Expo Go में splash की जगह आपका आइकन दिखता है।
  • Charmotion की launch फ़ाइल कोई end event फ़ायर नहीं करती: 2.6 सेकंड रुकें, फिर आगे बढ़ें।

पहले से कोई कैरेक्टर या लोगो है? अपने कैरेक्टर को असली ऐप स्क्रीन में देखें: स्प्लैश, ऑनबोर्डिंग, लोडिंग और एम्प्टी स्टेट स्क्रीन। यह फ़्री है, आपके ब्राउज़र में चलता है और कुछ भी अपलोड नहीं होता।

क्या Expo की स्प्लैश स्क्रीन को ही एनिमेट किया जा सकता है?

नहीं। Native splash को expo-splash-screen config plugin से तय किया जाता है, जिसमें backgroundColor, image, imageWidth, resizeMode और dark variant होते हैं, और ये settings binary में compile हो जाती हैं (Expo)। अंदर से यह iOS की लॉन्च स्क्रीन और Android की स्प्लैश स्क्रीन ही है, उन्हीं सीमाओं के साथ।

{
  "expo": {
    "backgroundColor": "#0E1116",
    "plugins": [
      ["expo-splash-screen", {
        "backgroundColor": "#0E1116",
        "image": "./assets/icon-rest.png",
        "imageWidth": 160,
        "dark": { "backgroundColor": "#0E1116", "image": "./assets/icon-rest.png" }
      }]
    ]
  }
}

Expo सिर्फ़ एक exit fade देता है: SplashScreen.setOptions({ duration, fade }), जिसमें fade सिर्फ़ iOS पर चलता है और default duration 400 ms है। इससे ज़्यादा कुछ भी, जैसे आपके आइकन का pop होकर आना, एक React component होना चाहिए जिसे आप splash के ठीक बाद render करें। Expo के अपने animated splash उदाहरण भी यही करते हैं (Expo Blog)।

preventAutoHideAsync और hideAsync कैसे काम करते हैं?

preventAutoHideAsync() native splash को तब तक दिखाए रखता है जब तक आप hideAsync() (या hide()) कॉल नहीं करते। Expo के docs कहते हैं कि इसे global scope में बिना await किए कॉल करें, ताकि यह आपके पहले render से पहले चल जाए। फिर इसे ठीक उस पल hide करें जब आपका intro अपना पहला फ़्रेम draw कर सके, न पहले और न किसी मनमाने delay के बाद।

// 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 />;
}

यहाँ showApp आपकी अपनी React state है, एनिमेशन फ़ाइल से आने वाला event नहीं। Splash कब hide करना है और onDone कब कॉल करना है, यह intro component तय करता है।

Splash और intro के बीच सफ़ेद फ़्लैश से कैसे बचें?

सफ़ेद फ़्लैश का मतलब है कि native splash और आपके intro के बीच किसी अलग रंग की चीज़ draw हुई। हर gap हटाएँ:

  • हर जगह एक ही hex। Splash plugin के backgroundColor, ऐप के root backgroundColor और intro container के लिए एक ही value रखें। Expo का app config root color को "आपके किसी भी React view के पीछे" का बैकग्राउंड बताता है, और यह भी कहता है कि iOS पर इसके लिए expo-system-ui चाहिए (Expo)।
  • Dark mode भी। dark splash options सेट करें और intro का बैकग्राउंड उसी color scheme से चुनें।
  • सही समय पर hide करें। hideAsync() को mount पर नहीं, एनिमेशन फ़ाइल load होने के बाद कॉल करें। पहले hide करने पर कुछ पल के लिए खाली React tree दिखता है।
  • वही position। Intro के आइकन को splash के imageWidth पर, बीच में render करें, ताकि handoff में कोई झटका न लगे।

Evan Bacon का video splash उदाहरण यही नियम काले रंग के साथ लागू करता है: ऐप, splash और iOS splash, तीनों का बैकग्राउंड काला, native splash तब तक रुका रहता है जब तक video load न हो जाए, फिर वीडियो चलता है और splash hide हो जाता है (GitHub)।

Intro के लिए Rive, video या Lottie, क्या चुनें?

विकल्पकिसके लिए सहीकिन बातों का ध्यान रखें
Rive (@rive-app/react-native)एक छोटी vector फ़ाइल, जिसका intro आगे एक interactive मैस्कॉट (loading, success, error) में बदल जाता हैNative module: development build ज़रूरी; Rive की Expo गाइड में SDK 53+ और iOS 15.1+ बताए गए हैं
वीडियो (expo-video)Detailed, 3D या raster intro; full-screen revealफ़ाइल भारी; कोई interaction नहीं। सबसे आसान तरीका: opaque क्लिप, जिसका बैकग्राउंड splash के रंग से मेल खाए
Lottie (lottie-react-native)एक linear vector एनिमेशन, जिसे डिज़ाइनर पहले ही एक्सपोर्ट कर चुका हैशुरू से अंत तक चलता है; दूसरी स्टेट पर जाने के लिए फ़ाइलें या segments बदलने पड़ते हैं

अगर वही कैरेक्टर launch के बाद भी ऐप में दिखते रहना चाहिए, तो Rive से आपको दूसरा asset नहीं बनाना पड़ता। अगर intro एक बार का cinematic है, तो वीडियो में सबसे कम code लगता है। दोनों में handoff का तरीका एक ही रहता है। पूरी तुलना के लिए स्प्लैश स्क्रीन के लिए Lottie vs Rive vs video और development build setup के लिए Expo में Rive देखें।

Expo में Rive का लॉन्च इंट्रो कैसे चलाएँ?

यह component फ़ाइल load होने तक native splash को रोके रखता है, launch स्टेट मशीन चलाता है, Reduce Motion का ध्यान रखता है, और intro की लंबाई पूरी होने पर onDone कॉल करता है। इसमें Rive का मौजूदा React Native रनटाइम (Rive) और React Native का AccessibilityInfo (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>
  );
}

metro.config.js में riv को asset extension के रूप में register करें ताकि require काम करे, जैसा Expo में Rive में बताया गया है। Video intro के लिए Rive view की जगह expo-video player (Expo) लगाएँ और player के play के लिए तैयार होते ही splash hide करें।

Charmotion सेट में यह launch फ़ाइल शामिल है: LaunchStateMachine आपके आइकन या मैस्कॉट का 2.6 सेकंड का intro एक बार चलाता है और फिर resting pose पर रुक जाता है। Charmotion, Rive और video export करता है, Lottie नहीं।

Expo Go या dev build में मेरा splash सही क्यों नहीं दिखता?

क्योंकि इनमें से कोई भी असली build नहीं है। Expo के docs कहते हैं कि Expo Go स्प्लैश स्क्रीन की जगह आपका ऐप आइकन दिखाता है, और development builds भी config plugin की settings से पूरी तरह मेल नहीं खाते, इसलिए वे splash को release build पर टेस्ट करने की सलाह देते हैं।

  • Expo Go: न custom splash, न Rive, क्योंकि Rive के पैकेज में native code है (Expo)।
  • Development build: intro component बनाने के लिए अच्छा; splash का सही प्रीव्यू नहीं।
  • Release या preview build: रंग का मेल और handoff timing परखने की एकमात्र जगह। Cold start, light और dark mode, और Reduce Motion चालू करके टेस्ट करें।

app.json में splash settings बदलने के बाद native ऐप दोबारा build करें (local builds के लिए npx expo prebuild --clean); splash binary में शामिल होता है और JavaScript reload से अपडेट नहीं होता।

Expo में एनिमेटेड स्प्लैश स्क्रीन कैसे जोड़ें

  1. Static splash सेट करें. expo-splash-screen plugin में backgroundColor, image, imageWidth और dark सेट करें, और root backgroundColor भी वही रखें।
  2. Splash रोके रखें. अपने root layout में global scope में SplashScreen.preventAutoHideAsync() कॉल करें।
  3. Intro render करें. उसी बैकग्राउंड पर, splash के साइज़ वाले आइकन के साथ एक intro component दिखाएँ, Rive, expo-video या Lottie से।
  4. Hide करें और रुकें. Intro के draw होने लायक होते ही hideAsync() कॉल करें, फिर उसकी लंबाई पूरी होने के बाद आगे बढ़ें (Charmotion launch फ़ाइल के लिए 2.6 सेकंड), साथ में एक safety timeout रखें।
  5. Release build टेस्ट करें. Cold start, dark mode और Reduce Motion को Expo Go में नहीं, release या preview build में जाँचें।

अक्सर पूछे जाने वाले सवाल

क्या Expo splash image के लिए GIF इस्तेमाल कर सकते हैं?

Splash image native लॉन्च स्क्रीन दिखाती है, जो सिर्फ़ स्थिर इमेज दिखाती है। Splash के लिए static PNG इस्तेमाल करें और कोई भी एनिमेशन, चाहे GIF हो, वीडियो या Rive फ़ाइल, उसी बैकग्राउंड रंग पर पहली React स्क्रीन में चलाएँ।

क्या preventAutoHideAsync, Expo Go में काम करता है?

Function मौजूद है, लेकिन Expo Go आपके configured splash की जगह ऐप आइकन दिखाता है, इसलिए वहाँ handoff परखा नहीं जा सकता। Splash और intro साथ में कैसे दिखते हैं, यह जाँचने के लिए release build इस्तेमाल करें।

React Native में कैसे पता करें कि Rive लॉन्च इंट्रो खत्म हो गया है?

अगर फ़ाइल अपना event फ़ायर करती है, तो उसे सुनें। Charmotion का LaunchStateMachine कोई event फ़ायर नहीं करता: वह अपना 2.6 सेकंड का intro एक बार चलाकर resting pose पर रुक जाता है, इसलिए फ़ाइल load होते ही 2,600 ms का timer शुरू करें और उसके खत्म होने पर आगे बढ़ें।

स्रोत

संबंधित गाइड