CSS Animations With Reanimated 4.0

CSS Animations With Reanimated 4.0

The world of animations in mobile development using React Native has been growing steadily, with the efforts of Software Mansion paving a path to the Reanimated library. This library has transformed the old, static feel of mobile apps built with React Native into more interactive and engaging applications that capture the user’s attention. Reanimated provides a structured way of achieving animations. Now, with the release of Reanimated 4, we can bring web CSS animations and transitions into the mobile development process, making it easier to create highly cool and efficient animations to integrate with your business logic.

Enough chitchat let’s get into some code example

Prerequisite set up

Let us first start of with scaffolding a simple expo project. Run the command below

expo init fireproject

After that let us use yarn to add the reanimated 4 library to our project

yarn add react-native-reanimated@next

Run prebuild to update the native code in the ios and android directories.

yarn expo prebuild

Fire animation

We begin by importing the necessary components from react-native and react-native-reanimated.
Import the common View from react native and theAnimated and css are the main components that will aid in our animation. We also define constants for animation duration, the number of flames, and a color palette for our fire

import { View } from 'react-native';
import Animated, { css } from 'react-native-reanimated';

const ANIMATION_DURATION = 1500;
const FLAMES_COUNT = 4;

const COLORS = {
  black: '#111217',
  brownDark: '#612E25',
  brownLight: '#70392F',
  orange: '#FDAC01',
  red: '#F73B01',
  yellow: '#FFDC01',
};

In Our App component is where we will render the entire fire animation. We create our container, the fire itself, flames, and logs. To create the flames we are using Array.from , which creates an array from an iterable object, to generate a list of FLAMES_COUNT elements. We then map over the array and on each flame we return an Animated.View, allowing us to animate its properties. In the styles within the Animated.View, we assign a unique animationDelay to each flame, creating a staggered effect. We also alternate between flameEven and flameOdd animations to introduce some variation see the blow code.

export default function App() {
  return (
    <View style={styles.container}>
      <View style={styles.fire}>
        <View style={styles.flames}>
          {Array.from({ length: FLAMES_COUNT }).map((_, index) => (
            <Animated.View
              key={index}
              style={[
                styles.flame,
                {
                  animationDelay: (ANIMATION_DURATION / 4) * index,
                  animationName: index % 2 === 0 ? flameEven : flameOdd,
                },
              ]}
            />
          ))}
        </View>
        <View style={styles.logs}>
          <View style={[styles.log, styles.logDark]} />
          <View style={[styles.log, styles.logLight]} />
        </View>
      </View>

      <View>
        <Text style={{color: 'red'}}>
          Loading ....
        </Text>
      </View>
    </View>
  );
}

Now we see the magic of the CSS property from reanimated. With the variables falmeEven and flameOddwe are now able to define the animations using css.keyframes. These keyframes describe how the flames change over time. They control properties like backgroundColor, bottom, height, right, width, and zIndex. The different keyframes create the flickering and rising effect of the flames. The zIndex property is used to control the layering of the flames, ensuring they appear to overlap realistically.

const flameEven = css.keyframes({
  '0%': {
    backgroundColor: COLORS.yellow,
    bottom: '0%',
    height: '0%',
    right: '0%',
    width: '0%',
    zIndex: 1000000,
  },
  '25%': {
    bottom: '1%',
    height: '100%',
    right: '2%',
    width: '100%',
  },
  '40%': {
    backgroundColor: COLORS.orange,
    zIndex: 1000000,
  },
  '100%': {
    backgroundColor: COLORS.red,
    bottom: '150%',
    height: '0%',
    right: '170%',
    width: '0%',
    zIndex: -10,
  },
});

const flameOdd = css.keyframes({
  '0%': {
    backgroundColor: COLORS.yellow,
    bottom: '0%',
    height: '0%',
    right: '0%',
    width: '0%',
    zIndex: 1000000,
  },
  '25%': {
    bottom: '2%',
    height: '100%',
    right: '1%',
    width: '100%',
  },
  '40%': {
    backgroundColor: COLORS.orange,
    zIndex: 1000000,
  },
  '100%': {
    backgroundColor: COLORS.red,
    bottom: '170%',
    height: '0%',
    right: '150%',
    width: '0%',
    zIndex: -10,
  },
});

We finally have the normal styles object we use to style our components as need be only that now we pull them using the css.create With it, we now define the layout, sizes, colors, and other visual properties. The flames container is rotated to give the flames a more dynamic appearance. The logs are positioned and rotated to create the illusion of stacked wood.

const styles = css.create({
  fire: {
    alignItems: 'center',
    maxWidth: 300,
    width: '40%',
  },
  container: {
    alignItems: 'center',
    backgroundColor: COLORS.black,
    flex: 1,
    justifyContent: 'center',
  },
  flame: {
    animationDuration: ANIMATION_DURATION,
    animationIterationCount: 'infinite',
    animationTimingFunction: 'ease-in',
    backgroundColor: COLORS.yellow,
    borderRadius: 40,
    position: 'absolute',
  },
  flames: {
    aspectRatio: 1,
    transform: [{ rotate: '45deg' }],
    width: '60%',
  },
  log: {
    borderRadius: 50,
    height: '100%',
    left: '50%',
    position: 'absolute',
    width: '100%',
  },
  logDark: {
    backgroundColor: COLORS.brownDark,
    transform: [{ translateX: '-50%' }, { rotate: '-20deg' }],
  },
  logLight: {
    backgroundColor: COLORS.brownLight,
    transform: [{ translateX: '-50%' }, { rotate: '20deg' }],
  },
  logs: {
    aspectRatio: 6,
    width: '100%',
  },
});

Running the application

It is important to note that the reanimated 4 is still in beta version though it is pretty stable. A kink that needs to be worked out is that it doesn’t work with Expo Go as of now. You need to have a development build or create a release apk. To create an apk with the changes we have just added simply navigate to the android folder in the application and run

/gradlew assembleRelease

After that, the apk will be in the app/build/outputs/apk folder. Grab that and install it on an emulator or physical device and voila

Conclusion

This example demonstrates how to create a campfire animation using React Native and react-native-reanimated. By combining CSS keyframes, styling, and the Animated API, we can achieve complex and performant animations in our React Native applications. This approach offers a declarative way to define animations, making the code easier to understand and maintain. This also means web developers can take their CSS skills and bring them to mobile development.
Till next time happy coding.