I have a TabView inside a ImageBackground in react-native app. The TabView does not show up but it is displayed when given as a parent element.
<ImageBackground source={require('../assets/images/loginBg.png')} style={styles.container}>
<TabView
navigationState={this.state}
renderScene={SceneMap({
first: FirstRoute,
second: SecondRoute,
})}
onIndexChange={index => this.setState({ index })}
initialLayout={{ width: Dimensions.get('window').width }}
style={innerStyles.innerContainer}
/>
</ImageBackground >
);
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ffffff',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
height: '50%',
},
});
const innerStyles = StyleSheet.create({
innerContainer: {
flex: 1,
},
scene: {
flex: 1,
},
});
You have to reconstruct the headers using the RenderTabBar function. I made an example of using the imageBackground that you want in the answer.
import * as React from 'react';
import { View, TouchableOpacity, StyleSheet, ImageBackground } from 'react-native';
import { TabView, SceneMap } from 'react-native-tab-view';
import Animated from 'react-native-reanimated';
const FirstRoute = () => (
<View style={[styles.container, { backgroundColor: '#ff4081' }]} />
);
const SecondRoute = () => (
<View style={[styles.container, { backgroundColor: '#673ab7' }]} />
);
export default class TabViewExample extends React.Component {
state = {
index: 0,
routes: [
{ key: 'first', title: 'First' },
{ key: 'second', title: 'Second' },
],
};
_handleIndexChange = index => this.setState({ index });
_renderTabBar = props => {
const inputRange = props.navigationState.routes.map((x, i) => i);
return (
<View style={styles.tabBar}>
{props.navigationState.routes.map((route, i) => {
const color = Animated.color(
Animated.round(
Animated.interpolate(props.position, {
inputRange,
outputRange: inputRange.map(inputIndex =>
inputIndex === i ? 255 : 0
),
})
),
0,
0
);
return (
<ImageBackground
source={{uri: "https://cdn.pixabay.com/photo/2015/07/27/19/47/turtle-863336__340.jpg"}}
style={{flex:1}}
>
<TouchableOpacity
style={styles.tabItem}
onPress={() => this.setState({ index: i })}>
<Animated.Text style={{ color }}>{route.title}</Animated.Text>
</TouchableOpacity>
</ImageBackground>
);
})}
</View>
);
};
_renderScene = SceneMap({
first: FirstRoute,
second: SecondRoute,
});
render() {
return (
<TabView
navigationState={this.state}
renderScene={this._renderScene}
renderTabBar={this._renderTabBar}
onIndexChange={this._handleIndexChange}
/>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
tabBar: {
flexDirection: 'row',
paddingTop: 24,
},
tabItem: {
flex: 1,
alignItems: 'center',
padding: 16,
},
});
Related
I have a horizontal ScrollView, all items have different widths
Is there a way to scroll one by one, so it would stop in the center of each item?
If the first answer to question is yes, then is there a way to know the index of item (that is centered), so I can change the index of selected dot?
https://snack.expo.dev/#drujik/horizontal-scroll-diff-widths
Example for: https://i.stack.imgur.com/thKLv.gif
I'm using FlatList and its props.
More information: https://reactnative.dev/docs/flatlist
import * as React from "react";
import { StyleSheet, Dimensions, FlatList, Text, View } from "react-native";
const data = [
{
text: "Page1",
width: 300,
},
{
text: "Page2",
width: 250,
},
{
text: "Page3",
width: 200,
},
];
const DOT_SIZE = 8;
const { width } = Dimensions.get("window");
export default function App() {
const [indexDot, setIndexDot] = React.useState(0);
const onChangeDot = (event) => {
setIndexDot(Math.ceil(event.nativeEvent.contentOffset.x / width));
};
const renderPagination = React.useMemo(() => {
return (
<View style={styles.wrapPagination}>
{data.map((_, index) => {
return (
<View
key={index}
style={[
styles.dot,
{
backgroundColor:
indexDot === index ? "#E7537A" : "rgba(0, 0, 0, 0.3)",
},
]}
/>
);
})}
</View>
);
}, [data?.length, indexDot]);
const renderItem = ({ item }) => (
<View style={styles.wrapItem}>
<View
style={{
...styles.item,
width: item.width,
}}
>
<Text>{item.text}</Text>
</View>
</View>
);
return (
<>
<FlatList
horizontal
pagingEnabled
disableIntervalMomentum
showsHorizontalScrollIndicator={false}
data={data}
renderItem={renderItem}
scrollEventThrottle={200}
onMomentumScrollEnd={onChangeDot}
/>
{renderPagination}
</>
);
}
const styles = StyleSheet.create({
wrapPagination: {
flexDirection: "row",
flex: 1,
justifyContent: "center",
alignItems: "center",
},
dot: {
height: DOT_SIZE,
width: DOT_SIZE,
borderRadius: DOT_SIZE / 2,
marginHorizontal: 3,
},
wrapItem: {
width,
padding: 20,
alignItems: "center",
justifyContent: "center",
},
item: {
alignItems: "center",
justifyContent: "center",
borderWidth: 1,
},
});
You can achieve this by react-native-snap-carousel and For dot, You can use pagination.
import Carousel, { Pagination } from 'react-native-snap-carousel';
const [active, setActive] = useState(0)
const [data, setData] = useState([])
<Carousel
keyExtractor={(_, index) => `id-${index}`}
data={data}
renderItem={renderItem}
onSnapToItem={setActive} />
<Pagination
dotsLength=length}
activeDotIndex={active}
dotStyle={{ backgroundColor: colors.blue }}
inactiveDotStyle={{ backgroundColor: colors.gray }}
inactiveDotScale={1}
inactiveDotOpacity={1} />
react-native-tab-view is not visible , not displayed on screen or not working because of the flex: 1 styling , we have to give flex: 1 styling inside parent view , otherwise it not displayed on screen .
for reference : https://github.com/satya164/react-native-tab-view/blob/main/example/src/CustomTabBarExample.tsx
solution :-
1st ex. with default tab bar -
import { StyleSheet, Text, View, useWindowDimensions } from 'react-native'
import React from 'react'
import { TabView, TabBar, SceneMap } from 'react-native-tab-view';
const BookingScreen = () => {
const layout = useWindowDimensions();
const FirstRoute = () => (
<View style={{ flex: 1, backgroundColor: '#ff4081' }} /> // here also writing flex: 1 is mandatory
);
const SecondRoute = () => (
<View style={{ flex: 1, backgroundColor: '#673ab7' }} /> // here also writing flex: 1 is mandatory
);
const [index, setIndex] = React.useState(0);
const [routes, setRoutes] = React.useState([
{ key: 'first', title: 'First' },
{ key: 'second', title: 'Second' },
]);
const renderScene = SceneMap({
first: FirstRoute,
second: SecondRoute,
// first: FeedbackScreen,
// second: ProfileScreen,
});
return (
<>
<View style={{ flex: 1 }}> // wrtie flex: 1 inside parent view its mandatory ***
<TabView
navigationState={{ index, routes }}
renderScene={renderScene}
onIndexChange={setIndex}
initialLayout={{ width: layout.width }}
/>
</View>
</>
)
}
export default BookingScreen
2nd ex. with custom tab bar -
import { StyleSheet, Text, View, useWindowDimensions } from 'react-native'
import React from 'react'
import { TabView, TabBar, SceneMap } from 'react-native-tab-view';
const BookingScreen = () => {
const [index, setIndex] = React.useState(0);
const [routes, setRoutes] = React.useState([
{ key: 'first', title: 'First' },
{ key: 'second', title: 'Second' },
]);
const _renderTabBar = props => (
<TabBar
{...props}
style={{ backgroundColor: '#fafafa' }}
tabStyle={[styles.tab, { height: 38, maxHeight: 38, minHeight: 38, padding: 0 }]}
labelStyle={[styles.label, { color: colors.text, }]}
indicatorStyle={{ backgroundColor: 'blue' }}
/>
);
return (
<>
<View style={{ flex: 1 }}> // giving flex:1 inside parent view is mandatory
<TabView
navigationState={{ index, routes }}
renderTabBar={_renderTabBar}
onIndexChange={setIndex}
renderScene={({ route }) => {
switch (route.key) {
case 'first':
return (<>
<View style={{ flex: 1, backgroundColor: '#ff4081' }} > // giving flex:1 is mandatory otherwise content will not shown
<Text style={{ color: 'black' }}>sadfghjkljhgfcgvhbj</Text>
</View>
</>);
case 'second':
return (<>
<View style={{ flex: 1, backgroundColor: '#673ab7' }} > // giving flex:1 is mandatory otherwise content will not shown
<Text style={{ color: 'black' }}>sadfghjkljhgfcgvhbj</Text>
</View>
</>);
default:
return null;
}
}}
/>
</View>
</>
)
}
export default BookingScreen
const styles = StyleSheet.create({
label: {
fontWeight: '600',
// fontSize: 12,
flexWrap: 'wrap',
// color: Colors.text,
// minWidth: Dimensions.get('window').width < 375 ? '100%' : '60%'
},
})
For future readers, a common problem is that the parent container doesn't have a defined height.
You must set the parent container height, for instance:
<View style={{height: "100%"}}> //or flex: 1
<TabView
navigationState={{ index, routes }}
renderScene={renderScene}
onIndexChange={setIndex}
initialLayout={{ width: layout.width }}
/>
</View>
Remove parent container will fix this problem.
return (
<TabView
navigationState={{ index, routes }}
renderScene={renderScene}
onIndexChange={setIndex}
initialLayout={{ width: layout.width }}
/>
)
I'm trying to accomplish the vertical carousel as shown in the below gif. I'm struck by the second screen, where when the user scrolls the data from bottom to top or vice versa both the content and image change, how to achieve this? looking forward to your help?enter image description here
I have included a snack example which is mostly similar to what you want. You can use reanimated, Flatlist achieve the animation:
Snack Link
Code:
import * as React from 'react';
import { Text, View, StyleSheet, FlatList, Dimensions } from 'react-native';
import Constants from 'expo-constants';
import Animated, {
useSharedValue,
useAnimatedScrollHandler,
useAnimatedStyle,
interpolate,
Extrapolate,
} from 'react-native-reanimated';
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
const { width, height } = Dimensions.get('window');
const bottomHeight = height - 150 - 30 - Constants.statusBarHeight;
const data = [
{
title: 'data1',
image:
'https://assets.website-files.com/5f204aba8e0f187e7fb85a87/5f210a533185e7434d9efcab_hero%20img.jpg',
},
{
title: 'data2',
image:
'https://www.whoa.in/201604-Whoa/10-alone-broken-image-mobile-wallpaper-hd-image.jpg',
},
{
title: 'data3',
image:
'https://images.pexels.com/photos/674010/pexels-photo-674010.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500',
},
{
title: 'data4',
image:
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTntlma5HASL0HAM-KiC01A-JX4MxKousAA6A&usqp=CAU',
},
];
const ImageContent = ({ image, scrollValue, index }) => {
const animatedStyle = useAnimatedStyle(() => {
const inputRange = [index * bottomHeight, (index + 1) * bottomHeight];
const translateY = interpolate(
scrollValue.value,
inputRange,
[0, -150],
Extrapolate.CLAMP
);
return {
transform: [{ translateY }],
};
});
return (
<Animated.Image
source={{ uri: image }}
style={[styles.image, { zIndex: data.length - index }, animatedStyle]}
resizeMode="cover"
/>
);
};
const TopPart = React.memo(({ scrollValue }) => {
return (
<View style={styles.topPartContainer}>
{data.map(({ image }, index) => (
<ImageContent {...{ scrollValue, image, index }} />
))}
</View>
);
});
const Item = ({ item, index }) => {
return (
<View
style={[
styles.item,
]}>
<Text style={{ color: 'red' }}>{item.title}</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
topPartContainer: {
width: 150,
height: 150,
borderRadius: 75,
alignSelf: 'center',
overflow: 'hidden',
},
image: {
...StyleSheet.absoluteFillObject,
backgroundColor: '#fff',
borderRadius: 75,
},
item: {
width,
backgroundColor: '#fff',
justifyContent: 'center',
alignItems: 'center',
height: bottomHeight,
},
});
function App() {
const scrollValue = useSharedValue(0);
const handler = useAnimatedScrollHandler((event) => {
scrollValue.value = event.contentOffset.y;
});
return (
<View style={styles.container}>
<TopPart {...{ scrollValue }} />
<View style={{ flex: 1, paddingTop: 30, height: bottomHeight }}>
<AnimatedFlatList
contentContainerStyle={{ height: data.length * bottomHeight }}
showsVerticalScrollIndicator={false}
onScroll={handler}
scrollEventThrottle={16}
data={data}
pagingEnabled
keyExtractor={(item) => item.title}
renderItem={({ item, index }) => <Item {...{ item, index }} />}
/>
</View>
</View>
);
}
I'm not getting how to get the current item object of a flat list
I used react-native-swipeout and react-native-swipe-list-view and in both examples I stuck.
And on google I found very big answers. Which are not pointing only the particular issue which confused me a lot.
the below is the deleted function when I used react-native-swipeout plugin
const swipeSettings = {
left: [
{
text: 'Delete',
onPress: () => {
console.log('-----delete-----');
},
type: 'delete',
},
}
All I need is to get the current item object data like below inside onpress() when i tapped the delete button .
{
id: 1,
prodName : "abcdefg",
}
That's all, I came from native script background and in that framework I never faced such issue. Because the documentation was crystal clear. But here In react native everything seems to be complicated for me.
Kindly any one help me.
<FlatList
data={data}
keyExtractor={(item) => item.id}
renderItem={({item, index}) => (
<Swipeout {...swipeSettings}>
<View style={styles.listView}>
<Text style={styles.listViewText}>{item.prodName}</Text>
</View>
</Swipeout>
)}
/>
entire page
import React, {useState} from 'react';
import {View} from 'react-native-animatable';
import {
TextInput,
TouchableOpacity,
FlatList,
} from 'react-native-gesture-handler';
import Icon from 'react-native-vector-icons/FontAwesome';
import {StyleSheet, Pressable, Text, Button} from 'react-native';
import * as Animatable from 'react-native-animatable';
import Swipeout from 'react-native-swipeout';
import ButtonPressable from '../../components/ButtonPressable';
var sqlite_wrapper = require('./sqliteWrapper');
const DATA = [
{
prodName: 'Added data will look like this',
},
];
const swipeSettings = {
style: {
marginBottom: 10,
},
autoClose: false,
backgroundColor: 'transparent',
close: false,
disabled: false,
onClose: (sectionID, rowId, direction) => {
console.log('---onclose--');
},
onOpen: (sectionID, rowId, direction) => {
console.log('---onopen--');
},
right: [
{
backgroundColor: 'dodgerblue',
color: 'white',
text: 'Edit',
onPress: () => {
console.log('-----edit-----');
},
},
],
left: [
{
backgroundColor: 'red',
color: 'white',
text: 'Delete',
onPress: () => {
console.log('-----delete-----');
sqlite_wrapper.deleteById
},
type: 'delete',
// component : (<ButtonPressable text="delete" />)
},
],
// buttonWidth: 100,
};
const AddProductList = ({route, navigation}) => {
const {navData} = route.params;
const [prodName, setProdName] = useState('');
var [data, setData] = useState(DATA);
return (
<View style={styles.container}>
<Animatable.View
animation="bounceIn"
duration={1000}
style={styles.inputFieldView}>
<TextInput
style={styles.textInput}
onChangeText={(value) => setProdName(value)}
placeholder="Add the Product"
defaultValue={prodName}
/>
<TouchableOpacity
style={styles.addView}
onPress={() => {
sqlite_wrapper
.insert({prodName: prodName}, sqlite_wrapper.collection_product)
.then((result) => {
console.log('---result---');
console.log(result);
if (result.rowsAffected) {
fetchAllData();
}
});
function fetchAllData() {
sqlite_wrapper
.readAll(sqlite_wrapper.collection_product)
.then((resultData) => {
console.log('---resultData---');
console.log(resultData);
setData(resultData);
setProdName('');
});
}
// without sql this is how to update the state having a array
// const updatedArray = [...data];
// updatedArray.push({prodName: prodName});
// setData(updatedArray);
// setProdName('');
}}>
<Icon name="plus" size={16} style={styles.add} color="white" />
</TouchableOpacity>
</Animatable.View>
<Animatable.View
animation="bounceInLeft"
duration={1500}
style={{flex: 1}}>
<FlatList
data={data}
keyExtractor={(item) => item.id}
renderItem={({item, index}) => (
<Swipeout {...swipeSettings}>
<View style={styles.listView}>
<Text style={styles.listViewText}>{item.prodName}</Text>
</View>
</Swipeout>
)}
/>
</Animatable.View>
</View>
);
};
var styles = StyleSheet.create({
container: {
flex: 1,
},
inputFieldView: {
flexDirection: 'row',
alignItems: 'center',
alignSelf: 'stretch',
margin: 10,
},
textInput: {
flex: 1,
backgroundColor: '#b2ebf2',
borderTopLeftRadius: 7,
borderBottomLeftRadius: 7,
fontSize: 16,
},
addView: {
backgroundColor: '#0f4c75',
alignSelf: 'stretch',
alignItems: 'center',
justifyContent: 'center',
borderTopEndRadius: 7,
borderBottomEndRadius: 7,
padding: 9,
},
add: {
padding: 7,
},
listView: {
padding: 20,
backgroundColor: 'green',
margin: 0,
borderRadius: 0,
},
listViewText: {
color: 'white',
},
});
export default AddProductList;
So if I get you right you have one generic swipe setting that you want to adjust to each element in the list.
Try changing the renderItem of the Flatlist like this and let me know how it worked for you:
<FlatList
data={data}
keyExtractor={(item) => item.id}
renderItem={({ item, index }) => {
let right = [...swipeSettings.right]; <---- ADDED
let left = [...swipeSettings.left]; <---- ADDED
right[0].onPress = () => console.log('edit', item.prodName); <---- ADDED
left[0].onPress = () => console.log('delete', item.prodName); <---- ADDED
<Swipeout {...swipeSettings} {...{ right, left}} > <---- CHANGED
<View style={styles.listView}>
<Text style={styles.listViewText}>{item.prodName}</Text>
</View>
</Swipeout>
}}
/>
So what I have done here is sending the generic swipe settings to each instance of Swipeout but changed their "Left" and "Right" in order to overwrite their "onPress" function and adjust it to the rendered item.
I know it is hard to understand it like this and it's probably not the best explanation but I hope it will help you somehow.
EDIT
import React, { useState } from 'react';
import { View } from 'react-native-animatable';
import {
TextInput,
TouchableOpacity,
FlatList,
} from 'react-native-gesture-handler';
import Icon from 'react-native-vector-icons/FontAwesome';
import { StyleSheet, Pressable, Text, Button } from 'react-native';
import * as Animatable from 'react-native-animatable';
import Swipeout from 'react-native-swipeout';
import ButtonPressable from '../../components/ButtonPressable';
var sqlite_wrapper = require('./sqliteWrapper');
const DATA = [
{
prodName: 'Added data will look like this',
},
];
const AddProductList = ({ route, navigation }) => {
const { navData } = route.params;
const [prodName, setProdName] = useState('');
var [data, setData] = useState(DATA);
const renderItem = ({ item, index }) => {
const swipeSettings = {
style: {
marginBottom: 10,
},
autoClose: false,
backgroundColor: 'transparent',
close: false,
disabled: false,
onClose: (sectionID, rowId, direction) => {
console.log('---onclose--');
},
onOpen: (sectionID, rowId, direction) => {
console.log('---onopen--');
},
right: [
{
backgroundColor: 'dodgerblue',
color: 'white',
text: 'Edit',
onPress: () => console.log('-----edit-----', item.prodName)
},
],
left: [
{
backgroundColor: 'red',
color: 'white',
text: 'Delete',
onPress: () => {
console.log('-----delete-----', item.prodName);
sqlite_wrapper.deleteById
},
type: 'delete',
// component : (<ButtonPressable text="delete" />)
},
],
// buttonWidth: 100,
};
return (
<Swipeout {...swipeSettings}>
<View style={styles.listView}>
<Text style={styles.listViewText}>{item.prodName}</Text>
</View>
</Swipeout>
)
}
return (
<View style={styles.container}>
<Animatable.View
animation="bounceIn"
duration={1000}
style={styles.inputFieldView}>
<TextInput
style={styles.textInput}
onChangeText={(value) => setProdName(value)}
placeholder="Add the Product"
defaultValue={prodName}
/>
<TouchableOpacity
style={styles.addView}
onPress={() => {
sqlite_wrapper
.insert({ prodName: prodName }, sqlite_wrapper.collection_product)
.then((result) => {
console.log('---result---');
console.log(result);
if (result.rowsAffected) {
fetchAllData();
}
});
function fetchAllData() {
sqlite_wrapper
.readAll(sqlite_wrapper.collection_product)
.then((resultData) => {
console.log('---resultData---');
console.log(resultData);
setData(resultData);
setProdName('');
});
}
// without sql this is how to update the state having a array
// const updatedArray = [...data];
// updatedArray.push({prodName: prodName});
// setData(updatedArray);
// setProdName('');
}}>
<Icon name="plus" size={16} style={styles.add} color="white" />
</TouchableOpacity>
</Animatable.View>
<Animatable.View
animation="bounceInLeft"
duration={1500}
style={{ flex: 1 }}>
<FlatList
data={data}
keyExtractor={(item) => item.id}
renderItem={renderItem}
/>
</Animatable.View>
</View>
);
};
var styles = StyleSheet.create({
container: {
flex: 1,
},
inputFieldView: {
flexDirection: 'row',
alignItems: 'center',
alignSelf: 'stretch',
margin: 10,
},
textInput: {
flex: 1,
backgroundColor: '#b2ebf2',
borderTopLeftRadius: 7,
borderBottomLeftRadius: 7,
fontSize: 16,
},
addView: {
backgroundColor: '#0f4c75',
alignSelf: 'stretch',
alignItems: 'center',
justifyContent: 'center',
borderTopEndRadius: 7,
borderBottomEndRadius: 7,
padding: 9,
},
add: {
padding: 7,
},
listView: {
padding: 20,
backgroundColor: 'green',
margin: 0,
borderRadius: 0,
},
listViewText: {
color: 'white',
},
});
export default AddProductList;
This program is supposed to change the background color of each individual item from this list when it is clicked. For example, when one item is pressed it will turn from pink to blue. My main issue is figuring out how to make/ connect a function with the item so that it will change its background color.
import React, { useState } from 'react'; import { StyleSheet, Text, View, FlatList, TouchableOpacity } from 'react-native';
export default function App() {
const [people, setPeople] = useState([
{ name: 'Day 1', id: '1' },
{ name: 'Day 2', id: '2' },
{ name: 'Day 3', id: '3' },
]);
const pressHandler = (id) => {
setPeople((prevPeople) => {
return prevPeople.{/*changeColorfunction*/};
});
};
return (
<View style={styles.container}>
<Text>Task 1</Text>
<FlatList
numColumns={5}
keyExtractor={(item) => item.id}
data={people}
renderItem={({ item }) => (
<TouchableOpacity onPress={() => pressHandler(item.id)}>
<Text style={styles.item}>{item.name}</Text>
</TouchableOpacity>
)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 40,
paddingHorizontal: 20,
backgroundColor: '#fff',
},
item: {
flex: 1,
marginHorizontal: 10,
marginTop: 24,
padding: 7,
backgroundColor: 'pink',
fontSize: 14,
},
});
I would suggest you wrap the item into its own component and handle the logic internally for each item.
// ListItem.js
export default function ListItem(props) {
const { name } = props;
const [pressed, setPressed] = useState(false);
const onPress = () => {
setPressed(prevPressed => !prevPressed);
}
return (
<TouchableOpacity onPress={onPress}>
<View style={{ backgroundColor : pressed ? 'red' : 'blue' }}>
<Text style={styles.item}>{props.name}</Text>
</View>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
item: {
flex: 1,
marginHorizontal: 10,
marginTop: 24,
padding: 7,
fontSize: 14,
}
});
// App.js
export default function App() {
const [people, setPeople] = useState([
{ name: 'Day 1', id: '1' },
{ name: 'Day 2', id: '2' },
{ name: 'Day 3', id: '3' }
]);
return (
<View style={styles.container}>
<Text>Task 1</Text>
<FlatList
numColumns={5}
keyExtractor={(item) => item.id}
data={people}
renderItem={({ item }) => (
<ListItem name={item.name} />
)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 40,
paddingHorizontal: 20,
backgroundColor: '#fff',
}
});