DEV Community

Mazahir
Mazahir

Posted on

How to create Animated FlatList in React-Native

Hey guys, I am Mazahir.
Today we are gonna learn how to use Animated API with FlatList to create
beautiful animations.

Requirements

  • Latest version of expo and react-native installed
  • Basic of expo with typescript
  • Nothing else, Let's get started

Preview

Before we get our hands dirty, let's see what are we trying to make.
react-natve animated flatlist

Your project will end up looking like this.

Initialization

  • Create a new expo project

expo init -t expo-template-blank-typescript

  • After Creating a new project, We need some data to display. I am using faker to create fake data but you can use an API or Hard Coded data as well.

How to create fake data using faker

  • npm i faker
  • Paste this code snippet.
// Inside App.tsx
const fake : string[] = new Array(20).fill('test');
const data: data[] = fake.map(() => ({
    name: faker.name.findName(),
    job_title: faker.name.jobTitle(),
    email: faker.internet.email(),
    key: faker.random.alphaNumeric(10),
    avatar: faker.image.avatar(),
  }));
Enter fullscreen mode Exit fullscreen mode
  • I am using react-native-paper for styling. Its not necessary for you to install, but I highly recommend it.

npm i react-native-paper

FlatList & Animations

  • To create beautiful animations like I said, We first need a FlatList. Create a folder named components and add a file named list.tsx.

  • Add the required import statements.

// inside components/list.tsx
import * as React from "react";
import { Text, View, StyleSheet, Animated, Dimensions } from "react-native";
import { Avatar, Surface } from "react-native-paper";

const { height } = Dimensions.get("screen");
Enter fullscreen mode Exit fullscreen mode

I am getting the height of the screen as well, which will be useful later

  • Now, we will create a basic function and a normal flatlist
interface Data {
  name: string;
  email: string;
  job_title: string;
  key: string;
  avatar: string;
}

export default function List({ data }: { data: Data[] }) {
  return (
    <View style={styles.container}>
      <Animated.FlatList
        data={data}
        keyExtractor={(item) => item.key}
        renderItem={({ item, index }) => {

          return (
            <Animated.View>
              <Surface style={styles.surface}>
                <View style={{ flex: 0.3, justifyContent: "center" }}>
                  <Avatar.Image size={42} source={{ uri: item.avatar }} />
                </View>
                <View
                  style={{
                    flex: 0.7,
                    flexDirection: "column",
                    justifyContent: "center",
                  }}
                >
                  <Text style={{ fontSize: 22, fontWeight: "bold" }}>
                    {item.name}
                  </Text>
                  <Text style={{ fontSize: 14 }}>{item.job_title}</Text>
                </View>
              </Surface>
            </Animated.View>
          );
        }}
      />
    </View>
  );
}



const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
  },
  surface: {
    height: height * 0.1,
    marginTop: 15,
    padding: 8,
    marginHorizontal: 10,
    borderRadius: 8,
    flexDirection: "row",
  },
});
Enter fullscreen mode Exit fullscreen mode

Even if i add Animated.FlatList or Animated.View, it will work as normal View and FlatList.

Animations

  • Inside list.tsx, Create a ref for an animated value
    const scrollY = React.useRef(new Animated.Value(0)).current;
    This will store the scroll offset of the Flatlist.

  • To update the scrollY.

onScroll={Animated.event(
          [{ nativeEvent: { contentOffset: { y: scrollY } } }],
          { useNativeDriver: true }
        )}
Enter fullscreen mode Exit fullscreen mode

Here we assign y offset of the list to our ref, useNativeDriver is true, that's something we don't need to worry about right now

  • if you save the changes, everything should work fine but there are no animations.
  1. to animate list we need 2 things input range and output range
  2. You can think of input range and output range as key frames if u know what that means.
  3. To define it input range is a set of values at which you want to animate or change a value.
  4. Output range is set of values that react or change based on the input range. It's okay if u did not understand it.
  • Enough theory let's get some animation on the screen. Inside the renderItem function we will add
const inputRange = [
   -1,
   0,
   (height * 0.1 + 15) * index,
   (height * 0.1 + 15) * (index + 3),
 ];
Enter fullscreen mode Exit fullscreen mode

height * 0.1 because that the height of the item or the view according to the style, we add 15 because of the margin.

when the content offset is at -1 or 0 we don't want any changes to the view or item, but we want to start the animation as soon as the item touches the top and the animation to end when the 3rd element( 3rd element from the current item) touches the top.

  • Now to animate the opacity
const opacity = scrollY.interpolate({
   inputRange,
   outputRange: [1, 1, 1, 0],
 });
Enter fullscreen mode Exit fullscreen mode

we store the animated value in const opacity. scrollY.interpolate it takes 1 argument an object with 2 array the input range and the outputrange.

  • We also need to translateX or to move the view on the x-axis. so we create interpolated value.
const Offset = scrollY.interpolate({
   inputRange,
   outputRange: [0, 0, 0, 500],
 });
Enter fullscreen mode Exit fullscreen mode
  • That's it, We have all the values we need. The only thing left to do is just wire them up.
<Animated.View
        style={{
                transform: [{ translateX: Offset }],
                opacity: opacity,
              }}
            >
Enter fullscreen mode Exit fullscreen mode

if save the changes, You should have working animations. if you got an error or the code does not work then you can check it with the my completed code here

  • You can play around with the input range and output range and get different results

Conclusion

Animation in react native is pretty simple if you know what you are doing.

You can find the completed code here

I hope you enjoyed and learned something out of this.
Any suggestions or feedback would be awesome. :)

Thank you.

Discussion (0)