Hey folks, This article is about creating an animation for a Flat List in React Native. The project uses Animated for creating the animation.
The animation will look like this -
Prerequisites -
- Knowledge of React Native ~ Beginner Level
- Working React Native Environment - Expo or React Native setup
Inital Dependencies in react-native get started project -
Copied from package.json
file
"expo": "~44.0.0",
"expo-status-bar": "~1.2.0",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-native": "0.64.3",
"react-native-web": "0.17.1"
So let's get started -
Open the folder in terminal, where you want to create your project -
- Make folder
mkdir React_Native_Animation
- Run the command
cd React_Native_Animation
- Run the command
expo init .
- Select the first blank template.
- Run the command to open your folder in Virtual Studio Code
code .
- In Virtual Studio Code open
App.js
file and clear all the code.
Now let's code some gibberish...
In App.js
file
- import modules
import React from 'react'
import {View,Text,SafeAreaView,FlatList,StyleSheet,TouchableOpacity,Pressable} from 'react-native'
import { Animated } from 'react-native';
- Create a class component and export it
class SocialMediaPage extends React.Component {
}
export default SocialMediaPage;
- Add a render method in class and return a View with a Text Component and text as 'Hello'
render() {
return (
<View>
<Text>
Hello
</Text>
</View>
);
}
- Wrap the View component inside a
SafeAreaView
and create styles and assign styles to the components.
import React from 'react'
import {View,Text,SafeAreaView,FlatList,StyleSheet,TouchableOpacity,Pressable} from 'react-native'
import { Animated } from 'react-native';
class SocialMediaPage extends React.Component {
render() {
return (
<SafeAreaView
style={styles.container}
>
<View style={styles.container}>
<Text>
Hello
</Text>
</View>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
container:{
marginTop:20,
},
})
export default SocialMediaPage;
- Create a data variable inside the
SocialMediaPage
class component which will contains the Item objects for theFlatlist
data = [
{text:'Twitter'},
{text:'Facebook'},
{text:'Github'},
{text:'Whatsapp'},
{text:'Instagram'},
{text:'Snapchat'},
{text:'LinkedIn'},
{text:'Leetcode'},
{text:'Codechef'},
{text:'Koo'}
]
- Remove the
View
,TextComponent
and add aFlatlist
and pass the variable data indata
props and define thekeyExtractor
props of Flatlist.<FlatList data={this.data} keyExtractor={(item)=>{ return item.text}} />
- Create styles for
ItemSeparatorComponent
andItemComponent
ofFlatlist
.
const styles = StyleSheet.create({
container:{
marginTop:20,
},
itemSeparator:{
height:2.0,
backgroundColor:'black',
margin:2.0,
marginHorizontal:.0
},
itemContainer:{
flexDirection:'row',
height:70,
width:370,
borderColor:'blue',
borderWidth:1.0,
padding:16,
marginHorizontal:14.0,
marginVertical:4.0,
backgroundColor:'lightgrey',
}
})
- Define the props
ItemSeparatorComponent
andrenderItem
for theFlatList
.
ItemSeparatorComponent={
() =>{
return (
<View
style={styles.itemSeparator
}
>
</View>
)
}
}
showsVerticalScrollIndicator= {false}
renderItem={(items)=>{
return (
)
}
- In the
renderItem
props ofFlatlist
create a Text with text taken from data and wrap it inside a View which has theitemContainer
styles.
ItemSeparatorComponent={
() =>{
return (
<View
style={styles.itemSeparator
}
>
</View>
)
}
}
showsVerticalScrollIndicator= {false}
renderItem={(items)=>{
return (
<View
style={styles.itemContainer}
>
<Text>
{items.item.text}
</Text>
</View>
)
}
Animating
- Create a state variable inside the
SocialMediaPage
class component
state = {
selectedKey:'',
animation:new Animated.Value(0.0)
}
The animation is an animated value that will vary and will be used for animation. We will change the value of selectedKey
on pressing the Flatlist
Item and will then animate that particular item.
The Animated library has different constructors for different kinds of animations. The main four are -
Animated.spring - Used for bouncing animations or animation with a spring effect. Eg.
Animated.spring(this.state.animation,
{
tension:100,
duration:1,
friction:1,
toValue:50,
useNativeDriver:true,
}
).start()
Animated.stagger - Used for creating complex animations where each animation occurs after the previous animation has ended. Eg.
Animated.stagger(300,
[Animated.spring(this.state.animation,
{
tension:100,
duration:1,
friction:1,
toValue:50,
useNativeDriver:true,
}
),
Animated.spring(
this.state.animation,
{
tension:100,
duration:1,
friction:1,
toValue:0,
useNativeDriver:true,
}
)
]
).start();
Animated.timing - Used for creating complex animation and perform a series of animation. Eg.
Animated.timing(300,
[Animated.spring(this.state.animation,
{
tension:100,
duration:1,
friction:1,
toValue:50,
useNativeDriver:true,
}
),
Animated.spring(
this.state.animation,
{
tension:100,
duration:1,
friction:1,
toValue:0,
useNativeDriver:true,
}
)
]
).start();
Animated.parallel - Used for creating complex animations where each animation occurs in parallel. Eg.
Animated.parallel(300,
[Animated.spring(this.state.animation,
{
tension:100,
duration:1,
friction:1,
toValue:50,
useNativeDriver:true,
}
),
Animated.spring(
this.state.animation,
{
tension:100,
duration:1,
friction:1,
toValue:0,
useNativeDriver:true,
}
)
]
).start();
We will use Animation.stagger as shown in example in our project.
Create a
handleAnimation
function inside theSocialMediaPage
class component that will be called when you press on aFlatlist
Item.Defining the Animation in
handleAnimation
function
handleAnimation=()=>{
Animated.parallel(300,
[Animated.spring(this.state.animation,
{
tension:100,
duration:1,
friction:1,
toValue:50,
useNativeDriver:true,
}
),
Animated.spring(
this.state.animation,
{
tension:100,
duration:1,
friction:1,
toValue:0,
useNativeDriver:true,
}
)
]
).start();
}
- In the
renderItem
prop ofFlatlist
return two different views depending on the value ofselectedKey
{this.state.selectedKey === items.item.text &&
(
<Animated.View
style={[styles.itemContainer,{
transform:[
{translateX: this.state !=null ? this.state.animation : 0 }
]
}]}
>
<Text>
{items.item.text}
</Text>
</Animated.View>
)
}
{this.state.selectedKey != items.item.text &&
(
<View
style={styles.itemContainer}
>
<Text>
{items.item.text}
</Text>
</View>
)
}
The View component in the first condition is Animated.View as it will animate. The Animated.View component has a new style that is based on the animation value defined in state variable.
- Wrap the entire returned
FlatList
item with a Pressable and define itsonPress
prop. In the onPress function change the value of selectedKey usingthis.setState({})
and call thehandleAnimation
function.
Now renderItem
prop of Flatlist
would look like this -
renderItem={(items)=>{
return (
<Pressable
onPress={() => {
this.setState({
selectedKey:items.item.text
})
console.log(this.state.selectedKey)
this.handleAnimation()
}
}
>
{this.state.selectedKey === items.item.text &&
(
<Animated.View
style={[styles.itemContainer,{
transform:[
{translateX: this.state !=null ? this.state.animation : 0 }
]
}]}
>
<Text>
{items.item.text}
</Text>
</Animated.View>
)
}
{this.state.selectedKey != items.item.text &&
(
<View
style={styles.itemContainer}
>
<Text>
{items.item.text}
</Text>
</View>
)
}
</Pressable>
)
}
}
The flatList
component at this stage will be -
<FlatList
data={this.data}
keyExtractor={(item)=>{
return item.text}}
ItemSeparatorComponent={
() =>{
return (
<View
style={styles.itemSeparator
}
>
</View>
)
}
}
showsVerticalScrollIndicator= {false}
renderItem={(items)=>{
return (
<Pressable
onPress={() => {
this.setState({
selectedKey:items.item.text
})
console.log(this.state.selectedKey)
this.handleAnimation()
}
}
>
{this.state.selectedKey === items.item.text &&
(
<Animated.View
style={[styles.itemContainer,{
transform:[
{translateX: this.state !=null ? this.state.animation : 0 }
]
}]}
>
<Text>
{items.item.text}
</Text>
</Animated.View>
)
}
{this.state.selectedKey != items.item.text &&
(
<View
style={styles.itemContainer}
>
<Text>
{items.item.text}
</Text>
</View>
)
}
</Pressable>
)
}
}
The full code is -
import React from 'react'
import {View,Text,SafeAreaView,FlatList,StyleSheet,TouchableOpacity,Pressable} from 'react-native'
import { Animated } from 'react-native';
class SocialMediaPage extends React.Component {
data = [
{text:'Twitter'},
{text:'Facebook'},
{text:'Github'},
{text:'Whatsapp'},
{text:'Instagram'},
{text:'Snapchat'},
{text:'LinkedIn'},
{text:'Leetcode'},
{text:'Codechef'},
{text:'Koo'}
]
state = {
selectedKey:'',
animation:new Animated.Value(0.0)
}
handleAnimation=()=>{
Animated.stagger(300,
[Animated.spring(this.state.animation,
{
tension:100,
duration:1,
friction:1,
toValue:50,
useNativeDriver:true,
}
),
Animated.spring(
this.state.animation,
{
tension:100,
duration:1,
friction:1,
toValue:0,
useNativeDriver:true,
}
)
]
).start();
}
render() {
return (
<SafeAreaView
style={styles.container}
>
<FlatList
data={this.data}
keyExtractor={(item)=>{
return item.text}}
ItemSeparatorComponent={
() =>{
return (
<View
style={styles.itemSeparator
}
>
</View>
)
}
}
showsVerticalScrollIndicator= {false}
renderItem={(items)=>{
return (
<Pressable
onPress={() => {
this.setState({
selectedKey:items.item.text
})
console.log(this.state.selectedKey)
this.handleAnimation()
}
}
>
{this.state.selectedKey === items.item.text &&
(
<Animated.View
style={[styles.itemContainer,{
transform:[
{translateX: this.state !=null ? this.state.animation : 0 }
]
}]}
>
<Text>
{items.item.text}
</Text>
</Animated.View>
)
}
{this.state.selectedKey != items.item.text &&
(
<View
style={styles.itemContainer}
>
<Text>
{items.item.text}
</Text>
</View>
)
}
</Pressable>
)
}
}
/>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
container:{
marginTop:20,
},
itemSeparator:{
height:2.0,
backgroundColor:'black',
margin:2.0,
marginHorizontal:.0
},
itemContainer:{
flexDirection:'row',
height:70,
width:370,
borderColor:'blue',
borderWidth:1.0,
padding:16,
marginHorizontal:14.0,
marginVertical:4.0,
backgroundColor:'lightgrey',
}
})
export default SocialMediaPage;
Important Things to Note -
- Define proper animation in handleAnimation() function.
- Properly render different components in Flatlist based on condition on the value of this.state.selectedKey.
- When this.state.selectedKey = item.key render Animated.View component.
Voohooooooo!! We have completed the project. Cheers !!
Follow me on Twitter for more tech content on React Native and Flutter.