How to make splash animation in react-native with react-native-bootsplash and react-native-animated.

Harish GautamHarish Gautam
5 min read

Hello Guys today I will show you to make a beautiful animated splash screen using react-native. So lets get started.

Start with react native setup

I assume you have already setup the react-native project. Please visit this links for necessary setups of react-native app, react-native navigation, react-native-reanimated.

Once this setups are done lets start with react-native bootsplash

  1. Lest first install react-native-bootsplash

     yarn add react-native-bootsplash
    
  1. Next step is asset generation.

    Create an "assets" folder in root and save the logo.png in it.

     yarn react-native generate-bootsplash assets/logo.svg \
       --platforms=android,ios \
       --background=F5FCFF \
       --logo-width=100 \
       --assets-output=assets \
       --flavor=main \
       --html=index.html
    
  2. To setup the splash screen in ios
    Edit the ios/YourProjectName/AppDelegate.mm file:

     #import "AppDelegate.h"
     #import "RNBootSplash.h" // ⬅️ add the header import
    
     // …
    
     @implementation AppDelegate
    
     // …
    
     // ⬇️ Add this before file @end (when bridgeless is enabled)
     - (void)customizeRootView:(RCTRootView *)rootView {
       [RNBootSplash initWithStoryboard:@"BootSplash" rootView:rootView]; // ⬅️ initialize the splash screen
     }
    
     @end
    
  3. To setup the splash screen in android

    1. Edit your android/app/src/main/res/values/styles.xml file:
    <resources>

      <style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
          <!-- Your base theme customization -->
      </style>

      <!-- BootTheme should inherit from Theme.BootSplash or Theme.BootSplash.EdgeToEdge -->
      <style name="BootTheme" parent="Theme.BootSplash">
        <item name="bootSplashBackground">@color/bootsplash_background</item>
        <item name="bootSplashLogo">@drawable/bootsplash_logo</item>
        <item name="postBootSplashTheme">@style/AppTheme</item>
      </style>

    </resources>
  1. Edit your android/app/src/main/AndroidManifest.xml file:
    <manifest xmlns:android="http://schemas.android.com/apk/res/android">

      <!-- … -->

      <application
        android:name=".MainApplication"
        android:label="@string/app_name"
        android:icon="@mipmap/ic_launcher"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:allowBackup="false"
        android:theme="@style/AppTheme"> <!-- Apply @style/AppTheme on .MainApplication -->
        <activity
          android:name=".MainActivity"
          android:label="@string/app_name"
          android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
          android:launchMode="singleTask"
          android:windowSoftInputMode="adjustResize"
          android:exported="true"
          android:theme="@style/BootTheme"> <!-- Apply @style/BootTheme on .MainActivity -->
          <!-- … -->
        </activity>
      </application>
    </manifest>
  1. Finally edit your android/app/src/main/java/com/yourprojectname/MainActivity.kt file:
    // Kotlin (react-native >= 0.73)
    // …

    // add these required imports:
    import android.os.Bundle
    import com.zoontek.rnbootsplash.RNBootSplash

    class MainActivity : ReactActivity() { {

      // …

      override fun onCreate(savedInstanceState: Bundle?) {
        RNBootSplash.init(this, R.style.BootTheme) // ⬅️ initialize the splash screen
        super.onCreate(savedInstanceState) // super.onCreate(null) with react-native-screens
      }
    }

Once the setup is done

  1. Create a two functional components 'SplashScreen' and 'HomeScreen'

    💡
    Also make sure to add SplashScreen on top of Stack.Navigator
import {Button, StyleSheet, Text, View} from 'react-native';
import React from 'react';

function SplashScreen({navigation}: any) {
  return (
    <View style={styles.container}>
      <Text>Splash screen</Text>
      <Button
        title="Go to Details"
        onPress={() => navigation.navigate('Details')}
      />
    </View>
  );
}

export default SplashScreen;

const styles = StyleSheet.create({
  container: {flex: 1, justifyContent: 'center', alignItems: 'center'},
});
import {Button, StyleSheet, Text, View} from 'react-native';
import React from 'react';

function HomeScreen({navigation}: any) {
  return (
    <View style={styles.container}>
      <Text>Home screen</Text>
    </View>
  );
}

export default HomeScreen;

const styles = StyleSheet.create({
  container: {flex: 1, justifyContent: 'center', alignItems: 'center'},
});
  1. In Splashscreen add this useEffect to hide the native splashscreen once lt is loaded.

       React.useEffect(() => {
         const init = async () => {
           // …do multiple sync or async tasks
         };
    
         init().finally(async () => {
           await BootSplash.hide({fade: true});
           console.log('BootSplash has been hidden successfully');
         });
       }, []);
    
  2. In splashScreen create this containers

  3.  const {height} = Dimensions.get('window');
     const slideY = useSharedValue(height);
     const circleSize = useSharedValue(50);
    
     const circleStyle = useAnimatedStyle(() => {
         return {
           width: circleSize.value,
           height: circleSize.value,
           borderRadius: circleSize.value / 2,
           transform: [{translateY: slideY.value}],
         };
     });
    
     return (
      <View style={styles.container}>
           <Image
             source={require('../../assets/argo_logo.png')}
             style={styles.logo}
           />
           <Animated.View style={[styles.circle, circleStyle]} />
         </View>
     )}
    
     export default SplashScreen;
    
     const styles = StyleSheet.create({
       container: {
         backgroundColor: '#64B54E',
         flex: 1,
         justifyContent: 'center',
         alignItems: 'center',
       },
       logo: {
         height: 130,
         width: '100%',
         objectFit: 'contain',
         marginTop: height > 875 ? -height * 0.05 : height * 0.02, //adjust this as per ur requirement
       },
       circle: {
         backgroundColor: 'white',
         position: 'absolute',
       },
     });
    
  4. Lets start the animation

  5.  React.useEffect(() => {
         const animate = async () => {
           await new Promise(resolve => setTimeout(resolve, 500)); // Initial delay
    
           // Slide animation
           slideY.value = withTiming(height / 2 - 80, {duration: 1500});
    
           await new Promise(resolve => setTimeout(resolve, 1500)); // Delay before circle animation
    
           // Circle animation
           circleSize.value = withTiming(2000, {duration: 1000});
    
           await new Promise(resolve => setTimeout(resolve, 750)); // Delay before changing status bar
    
           // Change status bar
           StatusBar.setBackgroundColor('white');
           StatusBar.setBarStyle('dark-content');
         };
    
         animate();
       }, []);
    
       React.useEffect(() => {
         setTimeout(() => {
           navigation.replace('HomeScreen');
         }, 3000); // Change the time as per your requirement
       }, []);
    

Meanwhile in HomeScreen component do this changes.

import {
  Button,
  Dimensions,
  StyleSheet,
  Text,
  View,
  Animated,
} from 'react-native';
import React from 'react';

const {height} = Dimensions.get('window');

function HomeScreen({navigation}: any) {
  const slideAnim = React.useRef(new Animated.Value(height)).current;

  React.useEffect(() => {
    Animated.timing(slideAnim, {
      toValue: 0,
      duration: 500,
      useNativeDriver: true,
    }).start();
  }, []);

  return (
    <Animated.View
      style={[styles.container, {transform: [{translateY: slideAnim}]}]}>
      <Text>Home screen</Text>
      <Button
        title="Go to Details"
        onPress={() => navigation.navigate('Details')}
      />
    </Animated.View>
  );
}

export default HomeScreen;

const styles = StyleSheet.create({
  container: {flex: 1, justifyContent: 'center', alignItems: 'center'},
});

Let me share you the final SplashScreen Code

import React from 'react';
import {Dimensions, Image, StatusBar, StyleSheet, View} from 'react-native';
import BootSplash from 'react-native-bootsplash';
import Animated, {
  useAnimatedStyle,
  useSharedValue,
  withTiming,
} from 'react-native-reanimated';

const {height} = Dimensions.get('window');

const SplashScreen = ({navigation}: any) => {
  React.useEffect(() => {
    const init = async () => {
      // …do multiple sync or async tasks
    };

    init().finally(async () => {
      await BootSplash.hide({fade: true});
      console.log('BootSplash has been hidden successfully');
    });
  }, []);

  React.useEffect(() => {
    setTimeout(() => {
      navigation.replace('PhoneScreen');
    }, 3000); // Change the time as per your requirement
  }, []);

  const slideY = useSharedValue(height);
  const circleSize = useSharedValue(50);

  const circleStyle = useAnimatedStyle(() => {
    return {
      width: circleSize.value,
      height: circleSize.value,
      borderRadius: circleSize.value / 2,
      transform: [{translateY: slideY.value}],
    };
  });

  React.useEffect(() => {
    const animate = async () => {
      await new Promise(resolve => setTimeout(resolve, 500)); // Initial delay

      // Slide animation
      slideY.value = withTiming(height / 2 - 80, {duration: 1500});

      await new Promise(resolve => setTimeout(resolve, 1500)); // Delay before circle animation

      // Circle animation
      circleSize.value = withTiming(2000, {duration: 1000});

      await new Promise(resolve => setTimeout(resolve, 750)); // Delay before changing status bar

      // Change status bar
      StatusBar.setBackgroundColor('white');
      StatusBar.setBarStyle('dark-content');
    };

    animate();
  }, []);

  return (
    <View style={styles.container}>
      <Image
        source={require('../../assets/argo_logo.png')}
        style={styles.logo}
      />
      <Animated.View style={[styles.circle, circleStyle]} />
    </View>
  );
};

export default SplashScreen;

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#64B54E',
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  logo: {
    height: 130,
    width: '100%',
    objectFit: 'contain',
    marginTop: height > 875 ? -height * 0.05 : height * 0.02,
  },
  circle: {
    backgroundColor: 'white',
    position: 'absolute',
  },
});

Hope You liked it.... do provide feedback

0
Subscribe to my newsletter

Read articles from Harish Gautam directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Harish Gautam
Harish Gautam