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.
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: Dimensions
is used to get the dimensions of the device screen. We destructure the width
property from the dimensions of the device’s window.
Lines 5–6: We calculate and export the ITEM_WIDTH
and ITEM_HEIGHT
. The width and height of the item are calculated based on the width of the output window.
Lines 8–15: We use StyleSheet.create
to define styles for the item container. The container has a fixed width and height, background color of "cornflowerblue
," and a border radius of 20
, giving it rounded corners.
Lines 17–18: A functional component Item
is created.
Line 21: We export functional component 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.
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
, and StyleSheet
from the react-native
library.
Line 3: We import the Item
component and the ITEM_HEIGHT
constant from the Item
file. We alias ITEM_HEIGHT
as DEFAULT_ITEM_HEIGHT
for clarity in our calculations.
Line 5: We define a constant BUFFER
with a value of 10. This buffer will be used to add padding around the item.
Line 6: We calculate a new ITEM_HEIGHT
which includes the BUFFER
on both the top and bottom, making it DEFAULT_ITEM_HEIGHT + BUFFER * 2
.
Lines 8–11: We use StyleSheet.create
to define styles for the component. We define an item
style with the following properties:
marginVertical: BUFFER
adds vertical margins of 10 units (top and bottom).
alignSelf: "center"
centers the item horizontally within its parent container.
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
.
propitems
is the object containing properties for color
and text
.
y
is an animated value representing the vertical scroll position.
index
is 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 AnimatedItem
component.
Lines 2–9: The translateY
value is calculated using Animated.add
to add the y
value with another interpolated value. The interpolation is based on the index
and ITEM_HEIGHT
. The extrapolateRight
property 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 interpolate
method maps input ranges to output ranges.
Line 5: inputRange
defines the range of values that the animated value y
is expected to take. In this case, it’s from 0 to a slightly higher value, which is influenced by the index and ITEM_HEIGHT
.
Line 6: outputRange
defines the corresponding output values for the specified input range. This will mean that as the y
value increases, the output will decrease, creating a downward motion.
Line 7: extrapolateRight: "clamp"
ensures that when the animated value y
goes 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.View
with styles that include a transform property with translateY
. This will cause the view to animate its vertical position based on the calculated translateY
value.
Line 17: Each AnimatedItem
is assigned a key
prop with the value of index
. This is important in React for efficient rendering and identifying each item uniquely in a list.
Line 19: The Item
is rendered in the Animated.View
. It receives two props, color
and text
, which are extracted from the propitems
prop.
Line 24: Finally, the AnimatedItem
component is exported as the default export.
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 AnimatedItem
in the first three lines of the code.
Line 5: The Animated.createAnimatedComponent()
method is used to create an animated version of a FlatList
component. This will allow us to animate the FlatList
component 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 data
array of size 10 is created. We create the key
, text
and set the color
. 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 value y
using Animated.Value(0)
. This value will be used to track the vertical scrolling position of the AnimatedFlatList
.
Lines 24–29: The onScroll
constant is created using Animated.event()
, which is a helper function for creating event handlers that update animated values. It listens for scroll events on the AnimatedFlatList
and updates the y
value accordingly. useNativeDriver
is 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 renderItem
function is defined to render each item of the list using another component called AnimatedItem
, passing in the y
value and the item’s index as props.
Lines 34–43: The MyAnimatedList
component returns an AnimatedFlatList
component, passing in the props, including data
, renderItem
, keyExtractor
, and onScroll
. This AnimatedFlatList
is essentially a regular FlatList
but with added animation capabilities controlled by the y
value and the scroll events tracked by onScroll
.
Line 46: Lastly, we export MyAnimatedList
as default.
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;
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 Dimensions
module from the react-native
library. The height
property is then extracted from the object returned by Dimensions.get("window")
.
Lines 4–7: To make the process easier, we can create a few constants, which are as follows:
isDisappearing
is set to -ITEM_HEIGHT
. It represents the point where an item is completely scrolled out of view above the list.
isTop
is set to 0
. This is the top of the list where an item is fully visible.
isBottom
is calculated as height - ITEM_HEIGHT
. This is the point where an item is fully visible at the bottom of the list.
isAppearing
is set to height
. It represents the point where an item is completely scrolled out of view below the list.
Lines 9–13: We use the interpolate
method to scale the items in the list based on their vertical position. We set the inputRange
as the constants defined earlier. Our outputRange
scale 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.
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