Accordion Panels is animated panels with Collapsible and Expandable functionality. Accordion panels are automatically controlled by itself and if user clicks on single panel then it will smoothly slide down and open itself but if you have clicked on any closed panel then it will first close the already open panel and then open the clicked panel using animation. We are using React Native’s Layout Animation to to open and close the panel. So in this tutorial we would going to implement Animated Accordion Collapsible Expandable Panel iOS Android Example Tutorial.
What we are doing in this project:
We are creating our own custom component to make animated Accordion effect now all we have to do is pass the data from the below class using Array and the data would automatically filled inside the Accordion.
To know how exactly it will work on your device see the below live screenshot:
Contents in this project React Native Animated Accordion Collapsible Expandable Panel iOS Android Example Tutorial:
1. Import Platform, LayoutAnimation, StyleSheet, View, Text, ScrollView, UIManager and TouchableOpacity component in your project.
1
2
3
|
import React, { Component } from ‘react’;
import { Platform, LayoutAnimation, StyleSheet, View, Text, ScrollView, UIManager, TouchableOpacity } from ‘react-native’;
|
2. Create a New class named as Accordion_Panel , This class is our custom Accordion class and used to render the complete Accordion Panel on device screen.
1
2
3
4
5
|
class Accordion_Panel extends Component {
}
|
3. Create constructor() method in Accordion_Panel class with a State named as updated_Height. The updated_Height state is used to manage the height of the Accordion according to content present inside it.
1
2
3
4
5
6
7
8
9
10
|
constructor() {
super();
this.state = {
updated_Height: 0
}
}
|
4. Create componentWillReceiveProps() inbuilt life cycle method inside the Accordion_Panel class. Using this method we would check the newly updated height of Accordion and updating the state. If you wish to study all the React Native life cycle methods then read our this tutorial.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
componentWillReceiveProps(update_Props) {
if (update_Props.item.expanded) {
this.setState(() => {
return {
updated_Height: null
}
});
}
else {
this.setState(() => {
return {
updated_Height: 0
}
});
}
}
|
5. Creating react’s own shouldComponentUpdate() method inside the Accordion_Panel class. Using this method we would improve our application experience and increasing its memory management power so it can be run more smoothly on your device with thousands of items inside it. It will stop our application from lagging or hanging with more data present condition. This method returns Boolean value.
1
2
3
4
5
6
7
8
9
10
11
|
shouldComponentUpdate(update_Props, nextState) {
if (update_Props.item.expanded !== this.props.item.expanded) {
return true;
}
return false;
}
|
6. Create the complete view of Accordion_Panel class in render’s return block . We are creating our own props this.props.onClickFunction , this.props.item.title and this.props.item.body inside the design layout. We would pass the props value from our next main class .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
render() {
return (
<View style={styles.Panel_Holder}>
<TouchableOpacity activeOpacity={0.7} onPress={this.props.onClickFunction} style={styles.Btn}>
<Text style={styles.Panel_Button_Text}>{this.props.item.title} </Text>
</TouchableOpacity>
<View style={{ height: this.state.updated_Height, overflow: ‘hidden’ }}>
<Text style={styles.Panel_text}>
{this.props.item.body}
</Text>
</View>
</View>
);
}
|
7. Complete source code for Accordion_Panel class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
class Accordion_Panel extends Component {
constructor() {
super();
this.state = {
updated_Height: 0
}
}
componentWillReceiveProps(update_Props) {
if (update_Props.item.expanded) {
this.setState(() => {
return {
updated_Height: null
}
});
}
else {
this.setState(() => {
return {
updated_Height: 0
}
});
}
}
shouldComponentUpdate(update_Props, nextState) {
if (update_Props.item.expanded !== this.props.item.expanded) {
return true;
}
return false;
}
render() {
return (
<View style={styles.Panel_Holder}>
<TouchableOpacity activeOpacity={0.7} onPress={this.props.onClickFunction} style={styles.Btn}>
<Text style={styles.Panel_Button_Text}>{this.props.item.title} </Text>
</TouchableOpacity>
<View style={{ height: this.state.updated_Height, overflow: ‘hidden’ }}>
<Text style={styles.Panel_text}>
{this.props.item.body}
</Text>
</View>
</View>
);
}
}
|
8. Creating our main class named as App . This would be our Main default export class.
1
2
3
4
5
6
|
export default class App extends Component {
}
|
9. Creating constructor() inside the App class and put the Layout Animation enable method. This method would enable the layout animation effect in your current project. No we would make a constant Array with 10 items and inside this we would set the default Accordion panel opening status and Accordion Title and Accordion body text. After that finally we would make a State named as AccordionData and set the Array inside the state.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
constructor() {
super();
if (Platform.OS === ‘android’) {
UIManager.setLayoutAnimationEnabledExperimental(true)
}
const array = [
{ expanded: false, title: “Panel 1”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 2”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 3”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 4”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 5”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 6”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 7”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 8”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 9”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 10”, body: “Hello Guys this is the Animated Accordion Panel.” },
];
this.state = { AccordionData: [...array] }
}
|
10. Create a function named as update_Layout inside the App class. We would call this function on Accordion item title clicked event. Using this function we would expand and collapse the Accordion panel and update the State value.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
update_Layout = (index) => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
const array = this.state.AccordionData.map((item) => {
const newItem = Object.assign({}, item);
newItem.expanded = false;
return newItem;
});
array[index].expanded = true;
this.setState(() => {
return {
AccordionData: array
}
});
}
|
11. Create the Root view inside render’s return block and call the Accordion_Panel class with Array data. We would call the Accordion_Panel class inside a ScrollView component.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
render() {
return (
<View style={styles.MainContainer}>
<ScrollView contentContainerStyle={{ paddingHorizontal: 10, paddingVertical: 5 }}>
{
this.state.AccordionData.map((item, key) =>
(
<Accordion_Panel key={key} onClickFunction={this.update_Layout.bind(this, key)} item={item} />
))
}
</ScrollView>
</View>
);
}
|
12. Creating Style.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
const styles = StyleSheet.create({
MainContainer: {
flex: 1,
justifyContent: ‘center’,
paddingTop: (Platform.OS === ‘ios’) ? 20 : 0
},
Panel_text: {
fontSize: 18,
color: ‘#000’,
padding: 10
},
Panel_Button_Text: {
textAlign: ‘center’,
color: ‘#fff’,
fontSize: 21
},
Panel_Holder: {
borderWidth: 1,
borderColor: ‘#FF6F00’,
marginVertical: 5
},
Btn: {
padding: 10,
backgroundColor: ‘#FF6F00’
}
});
|
13. Complete source code for App.js File :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
import React, { Component } from ‘react’;
import { Platform, LayoutAnimation, StyleSheet, View, Text, ScrollView, UIManager, TouchableOpacity } from ‘react-native’;
class Accordion_Panel extends Component {
constructor() {
super();
this.state = {
updated_Height: 0
}
}
componentWillReceiveProps(update_Props) {
if (update_Props.item.expanded) {
this.setState(() => {
return {
updated_Height: null
}
});
}
else {
this.setState(() => {
return {
updated_Height: 0
}
});
}
}
shouldComponentUpdate(update_Props, nextState) {
if (update_Props.item.expanded !== this.props.item.expanded) {
return true;
}
return false;
}
render() {
return (
<View style={styles.Panel_Holder}>
<TouchableOpacity activeOpacity={0.7} onPress={this.props.onClickFunction} style={styles.Btn}>
<Text style={styles.Panel_Button_Text}>{this.props.item.title} </Text>
</TouchableOpacity>
<View style={{ height: this.state.updated_Height, overflow: ‘hidden’ }}>
<Text style={styles.Panel_text}>
{this.props.item.body}
</Text>
</View>
</View>
);
}
}
export default class App extends Component {
constructor() {
super();
if (Platform.OS === ‘android’) {
UIManager.setLayoutAnimationEnabledExperimental(true)
}
const array = [
{ expanded: false, title: “Panel 1”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 2”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 3”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 4”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 5”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 6”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 7”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 8”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 9”, body: “Hello Guys this is the Animated Accordion Panel.” },
{ expanded: false, title: “Panel 10”, body: “Hello Guys this is the Animated Accordion Panel.” },
];
this.state = { AccordionData: [...array] }
}
update_Layout = (index) => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
const array = this.state.AccordionData.map((item) => {
const newItem = Object.assign({}, item);
newItem.expanded = false;
return newItem;
});
array[index].expanded = true;
this.setState(() => {
return {
AccordionData: array
}
});
}
render() {
return (
<View style={styles.MainContainer}>
<ScrollView contentContainerStyle={{ paddingHorizontal: 10, paddingVertical: 5 }}>
{
this.state.AccordionData.map((item, key) =>
(
<Accordion_Panel key={key} onClickFunction={this.update_Layout.bind(this, key)} item={item} />
))
}
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
MainContainer: {
flex: 1,
justifyContent: ‘center’,
paddingTop: (Platform.OS === ‘ios’) ? 20 : 0
},
Panel_text: {
fontSize: 18,
color: ‘#000’,
padding: 10
},
Panel_Button_Text: {
textAlign: ‘center’,
color: ‘#fff’,
fontSize: 21
},
Panel_Holder: {
borderWidth: 1,
borderColor: ‘#FF6F00’,
marginVertical: 5
},
Btn: {
padding: 10,
backgroundColor: ‘#FF6F00’
}
});
|
Screenshot: