React Native – How to create an animated Splash screen?

Idea

  • Create native Splash Screen to be an image with the same background color as the animation
  • Hide native Splash Screen as soon as JavaScript took control
  • Create React Native modal to show animated splash screen
  • Close this modal when everything is loaded

Create native splash screen

Create a splash screen activity in Android with theme

  • Create SplashActivity MVP
class SplashActivity : AppCompatActivity(), SplashContract.SplashView {

  private val presenter: SplashContract.Presenter = SplashPresenter(this)

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_splash)
  }

  override fun openReactApp() {
    Handler().postDelayed({
      val intent = Intent(this, MainActivity::class.java)
      startActivity(intent)
      finish()
    }, 3000)
  }

  override fun onResume() {
    super.onResume()
    presenter.onResume()
  }
}
class SplashContract {

  interface SplashView {
    fun openReactApp()
  }

  interface Presenter {
    fun onResume()
  }
}
class SplashPresenter(private val view: SplashContract.SplashView) : SplashContract.Presenter {
  override fun onResume() {
    view.openReactApp()
  }
}
  • Create layout activity_splash.xml
    You can set background color here android:background=”#000″
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="#000"
  tools:context="com.your.project.splash.SplashActivity">
</androidx.constraintlayout.widget.ConstraintLayout>
  • Run Android app
    You will still see the white blank screen before SplashActivity is loaded
    To fix this, embed theme into SplashActivity in AndroidManifest.xml
    Also, remove above android:background=”#000″ from layout xml file
...
    <activity
      android:name=".splash.SplashActivity"
      android:theme="@style/AppTheme.Launcher"
      android:exported="true">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
...
// src/main/res/values/styles.xml
<resources>
...
    <style name="AppTheme.Launcher">
        <item name="android:colorBackground">#000</item>
    </style>
....
</resources>

Install react-native-splash-screen

Hide native splash screen in JS

import SplashScreen from 'react-native-splash-screen';

const App = () => {
  useLayoutEffect(() => {
    const timeId = setTimeout(() => {
      SplashScreen.hide();
    }, 100);

    return () => {
      clearTimeout(timeId);
    };
  }, []);

  return (
    <Provider store={store}>
      <Splash />
      <Navigation />
    </Provider>
  );

Create React Native modal to show animated splash screen

import React, { FC, useState } from 'react';
import LottieView from 'lottie-react-native';
import Assets from '../../../assets';
import { Modal, StyleSheet } from 'react-native';
import { useSelector } from 'react-redux';
import { name } from 'src/state/slice';
import { TGlobaState } from 'src/types';

interface Props {}

const Splash: FC<Props> = () => {
  const [hasAnimationPlayedOnce, setHasAnimationPlayedOnce] = useState(false);

  const handleAnimationFinish = () => {
    setHasAnimationPlayedOnce(true);
  };

  const isAppInitialized = useSelector(
    (state: TGlobaState) => state[name].isAppInitialized
  );

  const isModalVisible = !(isAppInitialized && hasAnimationPlayedOnce);

  const onClose = () => {};
  return (
    <Modal
      animationType="none"
      transparent={true}
      visible={isModalVisible}
      onRequestClose={onClose}
    >
      <LottieView
        style={styles.modal}
        loop={false}
        autoPlay
        source={Assets.lottieFiles.planePath}
        colorFilters={[{ keypath: 'Plane', color: 'rgb(255, 100, 0)' }]}
        onAnimationFinish={handleAnimationFinish}
      />
    </Modal>
  );
};

const styles = StyleSheet.create({
  modal: {
    backgroundColor: '#3BACB6',
  },
});

export default Splash;

Close this modal when everything is loaded

import React, { useEffect } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { useDispatch, useSelector } from 'react-redux';
import { name } from 'src/state/slice';
import { TGlobaState } from 'src/types';
import TabStack from './components/TabStack';
import LoginStack from './components/LoginStack';
import { storeIsAppInitialized } from 'src/state/slice';

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////

const Routing: React.FC = () => {
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(storeIsAppInitialized(true));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const isLoggedIn = useSelector(
    (state: TGlobaState) => state[name].isLoggedIn
  );

  return (
    <NavigationContainer>
      {isLoggedIn ? <TabStack /> : <LoginStack />}
    </NavigationContainer>
  );
};

export default Routing;

Be the first to comment

Leave a Reply

Your email address will not be published.


*