How to animate a FlatList in React Native
The FlatList is a React Native framework component used to efficiently display data lists. Its purpose is to handle large lists by rendering only the items currently visible on the screen. As users scroll through the list, the FlatList dynamically renders and reuses components to display the new set of items in view. This approach provides better performance compared to rendering the entire list all at once.
In this Answer, we will be animating a FlatList using React Native’s Animated API.
The item
Let’s start by building the item that we will be using in the FlatList. We want to render each item as a bubble. We would also like the size of this item to be scalable to different screen sizes. Let’s see how we can achieve this using some basic components provided by the react-native library.
import React from "react";import { Dimensions, View, StyleSheet } from "react-native";const { width } = Dimensions.get("window");export const ITEM_WIDTH = width * 0.8;export const ITEM_HEIGHT = ITEM_WIDTH * 0.6;const styles = StyleSheet.create({item: {width: ITEM_WIDTH,height: ITEM_HEIGHT,backgroundColor: "cornflowerblue",borderRadius: 20,},});const Item = () => {return <View style={styles.item} />;};export default Item;
Lines 1–2: We import all the necessary components from React and React Native.
Line 4:
Dimensionsis used to get the dimensions of the device screen. We destructure thewidthproperty from the dimensions of the device’s window.Lines 5–6: We calculate and export the
ITEM_WIDTHandITEM_HEIGHT. The width and height of the item are calculated based on the width of the output window.Lines 8–15: We use
StyleSheet.createto define styles for the item container. The container has a fixed width and height, background color of "cornflowerblue," and a border radius of20, giving it rounded corners.Lines 17–18: A functional component
Itemis created.Line 21: We export functional component
Item.
Animating the item
We want to animate our list to bubble up each item as it scrolls into view. The item will then render completely once it is completely in view. When the item scrolls out of view, we want it to bubble down and move back into the screen. While this may sound tricky, it can be implemented easily by modifying the opacity and scale of the list items. In order to trigger these animations, we would need to know the position of each item on the screen. This will let react-native know when to trigger which animation. The vertical position is commonly referred to as the y value of a component. We will be following the same convention in this Answer.
Basic setup
Before implementing any animations, we need to set up some basic values. We will also use the Item that we created earlier.
import React from "react";import { Animated, Dimensions, StyleSheet } from "react-native";import Item, { ITEM_HEIGHT as DEFAULT_ITEM_HEIGHT } from "./Item";export const BUFFER = 10;export const ITEM_HEIGHT = DEFAULT_ITEM_HEIGHT + BUFFER * 2;const styles = StyleSheet.create({item: {marginVertical: BUFFER,alignSelf: "center",},});
Let’s see what’s happening in the code:
Lines 1–2: We import
Animated,Dimensions, andStyleSheetfrom thereact-nativelibrary.Line 3: We import the
Itemcomponent and theITEM_HEIGHTconstant from theItemfile. We aliasITEM_HEIGHTasDEFAULT_ITEM_HEIGHTfor clarity in our calculations.Line 5: We define a constant
BUFFERwith a value of 10. This buffer will be used to add padding around the item.Line 6: We calculate a new
ITEM_HEIGHTwhich includes theBUFFERon both the top and bottom, making itDEFAULT_ITEM_HEIGHT + BUFFER * 2.Lines 8–11: We use
StyleSheet.createto define styles for the component. We define anitemstyle with the following properties:marginVertical: BUFFERadds vertical margins of 10 units (top and bottom).alignSelf: "center"centers the item horizontally within its parent container.
Setting up the scroll
Let’s define our animated item that responds to the scroll position. This will allow us to create the basic scrolling animation for the list by simply manipulating the y value. The first thing we need to do is to create a functional component, AnimatedItem , that takes three parameters: propitems, y, and index.
propitemsis the object containing properties forcolorandtext.yis an animated value representing the vertical scroll position.indexis the index of the item being rendered.
const AnimatedItem = ({ propitems, y, index }) => {const translateY = Animated.add(y,y.interpolate({inputRange: [0, index * ITEM_HEIGHT],outputRange: [0, -index * ITEM_HEIGHT],extrapolateRight: "clamp",}));return (<Animated.Viewstyle={[styles.item,{ transform: { translateY } },]}key={index}><Item color={propitems.color} text={propitems.text} /></Animated.View>);};export default AnimatedItem;
Line 1: We define the
AnimatedItemcomponent.Lines 2–9: The
translateYvalue is calculated usingAnimated.addto add theyvalue with another interpolated value. The interpolation is based on theindexandITEM_HEIGHT. TheextrapolateRightproperty is set to"clamp", which means that any values outside the defined range will be clamped to the edge of the range.Line 4: The
interpolatemethod maps input ranges to output ranges.Line 5:
inputRangedefines the range of values that the animated valueyis expected to take. In this case, it’s from 0 to a slightly higher value, which is influenced by the index andITEM_HEIGHT.Line 6:
outputRangedefines the corresponding output values for the specified input range. This will mean that as theyvalue increases, the output will decrease, creating a downward motion.Line 7:
extrapolateRight: "clamp"ensures that when the animated valueygoes beyond the specified input range, it clamps the output to the last value in the output range. This prevents unwanted artifacts or unexpected behavior when scrolling.
Lines 11–16: This component returns an
Animated.Viewwith styles that include a transform property withtranslateY. This will cause the view to animate its vertical position based on the calculatedtranslateYvalue.Line 17: Each
AnimatedItemis assigned akeyprop with the value ofindex. This is important in React for efficient rendering and identifying each item uniquely in a list.Line 19: The
Itemis rendered in theAnimated.View. It receives two props,colorandtext, which are extracted from thepropitemsprop.Line 24: Finally, the
AnimatedItemcomponent is exported as the default export.
Creating the list
Now that our animated item has been created, we can now work on creating a FlatList and populating it with data. Let’s see how this is done in code.
import React from "react";import { Animated, FlatList } from "react-native";import AnimatedItem from "./AnimatedItem";const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);const colors = ["#FF99A1","#FFCC66","#FFFFB3","#B3FF99","#99C2FF","#E0CCFF",];const data = Array.from({ length: 10 }, (_, index) => ({key: `item${index}`,text: `Item ${index + 1}`,color: colors[index % colors.length],}));const MyAnimatedList = () => {const y = new Animated.Value(0);const onScroll = Animated.event([{ nativeEvent: { contentOffset: { y } } }],{useNativeDriver: false,});const renderItem = ({ index, item }) => (<AnimatedItem propitems={item} y={y} index={index} />);return (<AnimatedFlatListscrollEventThrottle={1}showsVerticalScrollIndicator={false}data={data}renderItem={renderItem}keyExtractor={(_, index) => index.toString()}{...{ onScroll }}/>);};export default MyAnimatedList;
Lines 1–3: We import the necessary libraries, and our
AnimatedItemin the first three lines of the code.Line 5: The
Animated.createAnimatedComponent()method is used to create an animated version of aFlatListcomponent. This will allow us to animate theFlatListcomponent using the capabilities provided by the Animated module, such as animating its position, opacity, scale, etc.Lines 7–14: We create an array of colors that we will use to color each item of the list.
Lines 16–20: The
dataarray of size 10 is created. We create thekey,textand set thecolor. These are properties that we will use to create our list of items.Lines 22–23: We create a functional component,
MyAnimatedList. Inside this component, we set up an animated valueyusingAnimated.Value(0). This value will be used to track the vertical scrolling position of theAnimatedFlatList.Lines 24–29: The
onScrollconstant is created usingAnimated.event(), which is a helper function for creating event handlers that update animated values. It listens for scroll events on theAnimatedFlatListand updates theyvalue accordingly.useNativeDriveris a boolean option that determines whether the animation should be executed on the native thread or not. We set this to false for better compatibility.Line 30: The
renderItemfunction is defined to render each item of the list using another component calledAnimatedItem, passing in theyvalue and the item’s index as props.Lines 34–43: The
MyAnimatedListcomponent returns anAnimatedFlatListcomponent, passing in the props, includingdata,renderItem,keyExtractor, andonScroll. ThisAnimatedFlatListis essentially a regularFlatListbut with added animation capabilities controlled by theyvalue and the scroll events tracked byonScroll.Line 46: Lastly, we export
MyAnimatedListas default.
Scrolling in action
Let’s see the progress we have made so far. The widget below contains the code for the Item, AnimatedItem, and AnimatedList components, along with some simple boilerplate code in the App.js file.
import React from "react";
import { View, Text } from "react-native";
export const ITEM_WIDTH = 360;
export const ITEM_HEIGHT = 180;
const Item = ({ color, text }) => {
return (
<View
style={{
width: ITEM_WIDTH,
height: ITEM_HEIGHT,
backgroundColor: color,
borderRadius: 20,
justifyContent: "center", // Center the text vertically
alignItems: "center", // Center the text horizontally
}}
>
<Text
style={{
color: "black",
fontSize: 30,
fontFamily: "Helvetica",
}}
>
{text}
</Text>
</View>
);
};
export default Item;
Implementing the animations
Now that the list scroll has been animated, we can focus on adding opacity and scale effects to the items. To create the bubble-in and bubble-out effects, we need to modify the scale of the items based on their current scroll positions. Since we have already made the effort earlier, this should be a simple process now.
import { Dimensions } from "react-native";const { height: height } = Dimensions.get("window");const isDisappearing = -ITEM_HEIGHT;const isTop = 0;const isBottom = height - ITEM_HEIGHT;const isAppearing = height;const scale = position.interpolate({inputRange: [isDisappearing, isTop, isBottom, isAppearing],outputRange: [0.5, 1, 1, 0.5],extrapolate: "clamp",});const opacity = position.interpolate({inputRange: [isDisappearing, isTop, isBottom, isAppearing],outputRange: [0.5, 1, 1, 0.5],});
Lines 1–2: We begin by first getting the height of our output window using
Dimensionsmodule from thereact-nativelibrary. Theheightproperty is then extracted from the object returned byDimensions.get("window").Lines 4–7: To make the process easier, we can create a few constants, which are as follows:
isDisappearingis set to-ITEM_HEIGHT. It represents the point where an item is completely scrolled out of view above the list.isTopis set to0. This is the top of the list where an item is fully visible.isBottomis calculated asheight - ITEM_HEIGHT. This is the point where an item is fully visible at the bottom of the list.isAppearingis set toheight. It represents the point where an item is completely scrolled out of view below the list.
Lines 9–13: We use the
interpolatemethod to scale the items in the list based on their vertical position. We set theinputRangeas the constants defined earlier. OuroutputRangescale is set to 0.5 when the item is disappearing or appearing and 1 when it is fully visible at the top or bottom of the list.Lines 15–18: A similar approach is used for both scale and opacity in this case.
Complete code
Let’s see what our animated list looks like with the opacity and scale animations applied.
import React from "react";
import { View, Text } from "react-native";
export const ITEM_WIDTH = 360;
export const ITEM_HEIGHT = 180;
const Item = ({ color, text }) => {
return (
<View
style={{
width: ITEM_WIDTH,
height: ITEM_HEIGHT,
backgroundColor: color,
borderRadius: 20,
justifyContent: "center", // Center the text vertically
alignItems: "center", // Center the text horizontally
}}
>
<Text
style={{
color: "black",
fontSize: 30,
fontFamily: "Helvetica",
}}
>
{text}
</Text>
</View>
);
};
export default Item;
Our list is animating beautifully with React Native’s Animated API. You can feel free to customize the animations and play around with the visuals. The options are limitless!
Free Resources