آموزش React Native – ساخت لیست Expanable


Expandable ListView یک ساختار متعارف از چندین لیست است که در صدها اپلیکیشن موبایل استفاده می شود.Expandable ListView یک لیست قابل گسترش یا باز شدن است که برای نمایش چندین دسته به همراه زیردسته ها در یک فضای کم استفاده می شود.تفاوتی که Expandable ListView با ListView معمولی یا Flatlist داره در اینکه ما آیتم ها رو فقط میتونیم در یک level نمایش بدیم اما در Expandable ما میتونیم آیتم ها رو در چنیدن level با قابلیت باز و بسته شدن زیردسته ها نمایش بدیم.در حال حاظر pure component برای ایجاد Expandable ListView وجود ندارد اما با طراحی یک کامپوننت سفارشی Expandable ListView سفارشی خودمون رو در React Native ایجاد میکنیم.
1 2 3 |
import React, { Component } from 'react'; import { Alert, LayoutAnimation, StyleSheet, View, Text, ScrollView, UIManager, TouchableOpacity, Platform, Image } from 'react-native'; |
2.ایجاد یک کلاس به نام Expandable_ListView.
1 2 3 4 5 |
class Expandable_ListView extends Component { } |
3.ایجاد ()constructor در کلاس Expandable_ListView . درون سازنده یک state به نام layout_Height تعریف میکنیم و مقدار اون رو 0 میزاریم.
1 2 3 4 5 6 7 8 9 10 |
constructor() { super(); this.state = { layout_Height: } } |
4.تعریف () componentWillReceiveProps با پارامتر nextProps در کلاس Expandable_ListView .در این method ما شرایطی رو برای هر آیتم مشخص می کنیم و بر اساس اون مقدار layout_height state رو تنظیم میکنیم.componentWillReceiveProps برای مقایسه مجدد داده ها زمانی که یک مقدار به عنوان prop تغییر می کند، استفاده می شود.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
componentWillReceiveProps(nextProps) { if (nextProps.item.expanded) { this.setState(() => { return { layout_Height: null } }); } else { this.setState(() => { return { layout_Height: } }); } |
5.تعریف() shouldComponentUpdate با پارامترهای nextProps و nextState در کلاس Expandable_ListView . متد shouldComponentUpdate برای افزایش عملکرد اپلیکیشن از طریق غیرفعال کردن re-rendering زمانی که کاربر یر روی یک data کلیک میکند.با اینکار مطمئن می شویم که فقط آیتم انتخاب شدهload شود نه کل لیست.
1 2 3 4 5 6 |
shouldComponentUpdate(nextProps, nextState) { if (this.state.layout_Height !== nextState.layout_Height) { return true; } return false; } |
6.ایجاد یک تابع به نام ()show_Selected_Category با پارامتر item در کلاس Expandable_ListView .این تابع برای نمایش آیتم انتخاب شده در لیست استفاده می شود.
1 2 3 4 5 6 |
show_Selected_Category = (item) => { // Write your code here which you want to execute on sub category selection. Alert.alert(item); } |
7.سرانجام ما آیتم ها و عنوان Expandable ListView رو در بلاک render’s return کلاس Expandable_ListView ایجاد می کنیم.
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 |
render() { return ( <View style={styles.Panel_Holder}> <TouchableOpacity activeOpacity={0.8} onPress={this.props.onClickFunction} style={styles.category_View}> <Text style={styles.category_Text}>{this.props.item.category_Name} </Text> <Image source={{ uri: 'https://reactnativecode.com/wp-content/uploads/2019/02/arrow_right_icon.png' }} style={styles.iconStyle} /> </TouchableOpacity> <View style={{ height: this.state.layout_Height, overflow: 'hidden' }}> { this.props.item.sub_Category.map((item, key) => ( <TouchableOpacity key={key} style={styles.sub_Category_Text} onPress={this.show_Selected_Category.bind(this, item.name)}> <Text> {item.name} </Text> <View style={{ width: '100%', height: 1, backgroundColor: '#000' }} /> </TouchableOpacity> )) } </View> </View> ); } |
سورس کد کامل کلاس Expandable_ListView .
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 |
class Expandable_ListView extends Component { constructor() { super(); this.state = { layout_Height: } } componentWillReceiveProps(nextProps) { if (nextProps.item.expanded) { this.setState(() => { return { layout_Height: null } }); } else { this.setState(() => { return { layout_Height: } }); } } shouldComponentUpdate(nextProps, nextState) { if (this.state.layout_Height !== nextState.layout_Height) { return true; } return false; } show_Selected_Category = (item) => { // Write your code here which you want to execute on sub category selection. Alert.alert(item); } render() { return ( <View style={styles.Panel_Holder}> <TouchableOpacity activeOpacity={0.8} onPress={this.props.onClickFunction} style={styles.category_View}> <Text style={styles.category_Text}>{this.props.item.category_Name} </Text> <Image source={{ uri: 'https://reactnativecode.com/wp-content/uploads/2019/02/arrow_right_icon.png' }} style={styles.iconStyle} /> </TouchableOpacity> <View style={{ height: this.state.layout_Height, overflow: 'hidden' }}> { this.props.item.sub_Category.map((item, key) => ( <TouchableOpacity key={key} style={styles.sub_Category_Text} onPress={this.show_Selected_Category.bind(this, item.name)}> <Text> {item.name} </Text> <View style={{ width: '100%', height: 1, backgroundColor: '#000' }} /> </TouchableOpacity> )) } </View> </View> ); } } |
9. تعریف ()constructor در کلاس App .ما layout animation رو درون سازنده فعال می کنیم.
1 2 3 4 5 6 7 8 |
constructor() { super(); if (Platform.OS === 'android') { UIManager.setLayoutAnimationEnabledExperimental(true) } |
10.تعریف یک آرایه از نوع const در کلاس App. این آرایه شامل آیتم های Expandable ListView است.
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 |
const array = [ { expanded: false, category_Name: "Mobiles", sub_Category: [{ id: 1, name: 'Mi' }, { id: 2, name: 'RealMe' }, { id: 3, name: 'Samsung' }, { id: 4, name: 'Infinix' }, { id: 5, name: 'Oppo' }, { id: 6, name: 'Apple' }, { id: 7, name: 'Honor' }] }, { expanded: false, category_Name: "Laptops", sub_Category: [{ id: 8, name: 'Dell' }, { id: 9, name: 'MAC' }, { id: 10, name: 'HP' }, { id: 11, name: 'ASUS' }] }, { expanded: false, category_Name: "Computer Accessories", sub_Category: [{ id: 12, name: 'Pendrive' }, { id: 13, name: 'Bag' }, { id: 14, name: 'Mouse' }, { id: 15, name: 'Keyboard' }] }, { expanded: false, category_Name: "Home Entertainment", sub_Category: [{ id: 16, name: 'Home Audio Speakers' }, { id: 17, name: 'Home Theatres' }, { id: 18, name: 'Bluetooth Speakers' }, { id: 19, name: 'DTH Set Top Box' }] }, { expanded: false, category_Name: "TVs by brand", sub_Category: [{ id: 20, name: 'Mi' }, { id: 21, name: 'Thomson' }, { id: 22, name: 'LG' }, { id: 23, name: 'SONY' }] }, { expanded: false, category_Name: "Kitchen Appliances", sub_Category: [{ id: 24, name: 'Microwave Ovens' }, { id: 25, name: 'Oven Toaster Grills (OTG)' }, { id: 26, name: 'Juicer/Mixer/Grinder' }, { id: 27, name: 'Electric Kettle' }] } ]; this.state = { AccordionData: [...array] } } |
11.ایجاد یک تابع به نام ()update_Layout با پارامتر index در کلاس App. در ابتدا ما layout animation رو فعال می کنیم و سپس layout رو با آیتم های جدید بروزرسانی می کنیم.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
update_Layout = (index) => { LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); const array = [...this.state.AccordionData]; array[index]['expanded'] = !array[index]['expanded']; this.setState(() => { return { AccordionData: array } }); } |
12.سرانجام ما کامپوننت Expandable_ListView در بلاک render’s return فراخوانی میکنیم.
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) => ( <Expandable_ListView key={item.category_Name} onClickFunction={this.update_Layout.bind(this, key)} item={item} /> )) } </ScrollView> </View> ); } |
13.ایجاد استایل.
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 |
const styles = StyleSheet.create({ MainContainer: { flex: 1, justifyContent: 'center', paddingTop: (Platform.OS === 'ios') ? 20 : , backgroundColor: '#F5FCFF', }, iconStyle: { width: 30, height: 30, justifyContent: 'flex-end', alignItems: 'center', tintColor: '#fff' }, sub_Category_Text: { fontSize: 18, color: '#000', padding: 10 }, category_Text: { textAlign: 'left', color: '#fff', fontSize: 21, padding: 10 }, category_View: { marginVertical: 5, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', backgroundColor: '#0091EA' }, Btn: { padding: 10, backgroundColor: '#FF6F00' } }); |
14.کد کامل فایل App.js
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 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
import React, { Component } from 'react'; import { Alert, LayoutAnimation, StyleSheet, View, Text, ScrollView, UIManager, TouchableOpacity, Platform, Image } from 'react-native'; class Expandable_ListView extends Component { constructor() { super(); this.state = { layout_Height: } } componentWillReceiveProps(nextProps) { if (nextProps.item.expanded) { this.setState(() => { return { layout_Height: null } }); } else { this.setState(() => { return { layout_Height: } }); } } shouldComponentUpdate(nextProps, nextState) { if (this.state.layout_Height !== nextState.layout_Height) { return true; } return false; } show_Selected_Category = (item) => { // Write your code here which you want to execute on sub category selection. Alert.alert(item); } render() { return ( <View style={styles.Panel_Holder}> <TouchableOpacity activeOpacity={0.8} onPress={this.props.onClickFunction} style={styles.category_View}> <Text style={styles.category_Text}>{this.props.item.category_Name} </Text> <Image source={{ uri: 'https://reactnativecode.com/wp-content/uploads/2019/02/arrow_right_icon.png' }} style={styles.iconStyle} /> </TouchableOpacity> <View style={{ height: this.state.layout_Height, overflow: 'hidden' }}> { this.props.item.sub_Category.map((item, key) => ( <TouchableOpacity key={key} style={styles.sub_Category_Text} onPress={this.show_Selected_Category.bind(this, item.name)}> <Text> {item.name} </Text> <View style={{ width: '100%', height: 1, backgroundColor: '#000' }} /> </TouchableOpacity> )) } </View> </View> ); } } export default class App extends Component { constructor() { super(); if (Platform.OS === 'android') { UIManager.setLayoutAnimationEnabledExperimental(true) } const array = [ { expanded: false, category_Name: "Mobiles", sub_Category: [{ id: 1, name: 'Mi' }, { id: 2, name: 'RealMe' }, { id: 3, name: 'Samsung' }, { id: 4, name: 'Infinix' }, { id: 5, name: 'Oppo' }, { id: 6, name: 'Apple' }, { id: 7, name: 'Honor' }] }, { expanded: false, category_Name: "Laptops", sub_Category: [{ id: 8, name: 'Dell' }, { id: 9, name: 'MAC' }, { id: 10, name: 'HP' }, { id: 11, name: 'ASUS' }] }, { expanded: false, category_Name: "Computer Accessories", sub_Category: [{ id: 12, name: 'Pendrive' }, { id: 13, name: 'Bag' }, { id: 14, name: 'Mouse' }, { id: 15, name: 'Keyboard' }] }, { expanded: false, category_Name: "Home Entertainment", sub_Category: [{ id: 16, name: 'Home Audio Speakers' }, { id: 17, name: 'Home Theatres' }, { id: 18, name: 'Bluetooth Speakers' }, { id: 19, name: 'DTH Set Top Box' }] }, { expanded: false, category_Name: "TVs by brand", sub_Category: [{ id: 20, name: 'Mi' }, { id: 21, name: 'Thomson' }, { id: 22, name: 'LG' }, { id: 23, name: 'SONY' }] }, { expanded: false, category_Name: "Kitchen Appliances", sub_Category: [{ id: 24, name: 'Microwave Ovens' }, { id: 25, name: 'Oven Toaster Grills (OTG)' }, { id: 26, name: 'Juicer/Mixer/Grinder' }, { id: 27, name: 'Electric Kettle' }] } ]; this.state = { AccordionData: [...array] } } update_Layout = (index) => { LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); const array = [...this.state.AccordionData]; array[index]['expanded'] = !array[index]['expanded']; this.setState(() => { return { AccordionData: array } }); } render() { return ( <View style={styles.MainContainer}> <ScrollView contentContainerStyle={{ paddingHorizontal: 10, paddingVertical: 5 }}> { this.state.AccordionData.map((item, key) => ( <Expandable_ListView key={item.category_Name} 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 : , backgroundColor: '#F5FCFF', }, iconStyle: { width: 30, height: 30, justifyContent: 'flex-end', alignItems: 'center', tintColor: '#fff' }, sub_Category_Text: { fontSize: 18, color: '#000', padding: 10 }, category_Text: { textAlign: 'left', color: '#fff', fontSize: 21, padding: 10 }, category_View: { marginVertical: 5, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', backgroundColor: '#0091EA' }, Btn: { padding: 10, backgroundColor: '#FF6F00' } }); |
دیدگاهتان را بنویسید