FlatList with ScrollTo in React Native - react-native

I'm new to React Native, I'm trying to make a FlatList in an application with Expo that will pull some categories of products from a Json, I managed to make the FlatList and also a Json simulation for testing, however I wish that by clicking on any item in the FlatList it directs the Scroll to the respective section, the same when using anchor with id in HTML.
For example: FlatList will display the categories: Combo, Side Dishes, Hot Dog, etc. For each category that is displayed by FlatList I have already created a View that will display products in this category.
What I want to do:
When you click on a category displayed by FlatList the Scroll scrolls to the View that displays the products of this category, that is, if you click on Combo the page scrolls to the View that displays the products of the Combo category, if you click on Side Dishes the page scrolls until the View that displays the products in the Side Dishes category, follows my code:
Follow my code: (it can be simulated here: https://snack.expo.io/#wendell_chrys/06944b)
import React, { useEffect, useState } from 'react';
import { View, Image, ImageBackground, Text, StyleSheet, ScrollView, Dimensions, FlatList, SafeAreaView, TouchableOpacity } from 'react-native';
import { AppLoading } from 'expo';
import Constants from 'expo-constants';
const DATA = [
{
id: "1",
title: "Combos",
categorie: "section1",
},
{
id: "2",
title: "Side Dishes",
categorie: "section2",
},
{
id: "3",
title: "Hot Dog",
categorie: "section3",
},
{
id: "4",
title: "Desserts",
categorie: "section4",
},
{
id: "5",
title: "Drinks",
categorie: "section5",
},
];
const renderItem = ({ item }) => {
return (
<Item
item={item}
/>
);
};
const Item = ({ item, onPress, style }) => (
<TouchableOpacity onPress={onPress} >
<Text style={styles.itenscategoria}>{item.title}</Text>
</TouchableOpacity>
);
export default function App() {
return (
<View style={styles.container}>
<View style={styles.categories}>
<FlatList
data={DATA}
horizontal
showsHorizontalScrollIndicator={false}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</View>
<ScrollView>
<View style={styles.section1}>
<Text>Combos</Text>
</View>
<View style={styles.section2}>
<Text>Side Dishes</Text>
</View>
<View style={styles.section3}>
<Text>Hot Dog</Text>
</View>
<View style={styles.section4}>
<Text>Desserts</Text>
</View>
<View style={styles.section5}>
<Text>Drinks</Text>
</View>
</ ScrollView>
</View >
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#000',
padding: 8,
},
categories: {
backgroundColor: '#FFFFFF',
width: '100%',
height: 50,
top: 10,
marginBottom:20,
},
itenscategoria: {
padding:15,
border: 1,
borderRadius:25,
marginRight:10,
},
section1: {
marginTop: 10,
backgroundColor: '#ccc',
width: '100%',
height: 200,
borderRadius: 10,
},
section2: {
marginTop: 10,
backgroundColor: '#ccc',
width: '100%',
height: 200,
borderRadius: 10,
},
section3: {
marginTop: 10,
backgroundColor: '#ccc',
width: '100%',
height: 200,
borderRadius: 10,
},
section4: {
marginTop: 10,
backgroundColor: '#ccc',
width: '100%',
height: 200,
borderRadius: 10,
},
section5: {
marginTop: 10,
backgroundColor: '#ccc',
width: '100%',
height: 200,
borderRadius: 10,
},
});

You can make use of scrollToIndex of FlatList
See complete code below, or the snack here.
import React, { useEffect, useState, useRef } from 'react';
import { View, Image, ImageBackground, Text, StyleSheet, ScrollView, Dimensions, FlatList, SafeAreaView, TouchableOpacity } from 'react-native';
import { AppLoading } from 'expo';
import Constants from 'expo-constants';
const DATA = [
{
id: "1",
title: "Combos",
categorie: "section1",
},
{
id: "2",
title: "Side Dishes",
categorie: "section2",
},
{
id: "3",
title: "Hot Dog",
categorie: "section3",
},
{
id: "4",
title: "Desserts",
categorie: "section4",
},
{
id: "5",
title: "Drinks",
categorie: "section5",
},
];
export default function App() {
const flatListRef = useRef();
const handleItemPress = (index) => {
flatListRef.current.scrollToIndex({ animated: true, index });
};
const renderItem = ({ item, index }) => {
return (
<Item
item={item}
onPress={() => handleItemPress(index)}
/>
);
};
const Item = ({ item, onPress, style }) => (
<TouchableOpacity onPress={onPress} >
<Text style={styles.itenscategoria}>{item.title}</Text>
</TouchableOpacity>
);
const renderDetails = ({ item, index }) => (
<View style={styles.section}>
<Text>{item.title}</Text>
</View>
);
return (
<View style={styles.container}>
<View style={styles.categories}>
<FlatList
data={DATA}
horizontal
showsHorizontalScrollIndicator={false}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</View>
<FlatList
ref={flatListRef}
data={DATA}
renderItem={renderDetails}
keyExtractor={(item) => item.id}
/>
</View >
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#000',
padding: 8,
},
categories: {
backgroundColor: '#FFFFFF',
width: '100%',
height: 50,
top: 10,
marginBottom:20,
},
itenscategoria: {
padding:15,
border: 1,
borderRadius:25,
marginRight:10,
},
section: {
marginTop: 10,
backgroundColor: '#ccc',
width: '100%',
height: 200,
borderRadius: 10,
},
});

Related

React Native Scrollview - scroll one by one (items with different widths)

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 Images FlatList Error "doesn't show the images"

enter image description here
I relied on this video, here's the github with the video code:
https://github.com/KasperKloster/ComponentsExplained/blob/main/App.js
https://www.youtube.com/watch?v=qGN3S0wO-OQ
i'm not getting to view the icon images in png and neither in svg, could they help me? I put a bacgroundColor in some random color just to see if the icons are there, and they are, only they are not showing up.. i also couldn't put logout at the bottom of the screen
Settings.js
import { SafeAreaView,Text, View, FlatList,
TouchableOpacity, StyleSheet, Image} from 'react-native';
import React, {useState} from 'react'
const Settings = () => {
const [data, setdata] = useState(DATA);
const [isRender, setisRender] = useState(false);
const DATA = [
{id: 1, text: 'Perfil', image: require('../../assets/images/user.png')},
{id: 2, text: 'Dark/Light mode', image: require('../../assets/images/light-up.png')},
{id: 3, text: 'TouchId', image: require('../../assets/images/fingerprint.png')},
{id: 4, text: 'Logout'},
]
const renderItem = ({item}) => {
return(
<TouchableOpacity
style= {styles.item}
>
<View style={ styles.avatarContainer }>
<Image loadingIndicatorSource={ item.image } style={ styles.avatar } />
</View>
<View>
<Text style={styles.text}>{item.text}</Text>
</View>
</TouchableOpacity>
)
}
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
keyExtractor={(item) => item.id.toString()}
renderItem={renderItem}
extraData={isRender}
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 20
//marginHorizontal: 21
},
item:{
borderBottomWidth: 1,
borderBottomColor: '#808080',
alignItems: 'flex-start',
flexDirection: 'row',
},
avatarContainer: {
backgroundColor: '#A0D800',
borderRadius: 100,
height: 30,
width: 30,
justifyContent: 'center',
alignItems: 'center',
},
avatar: {
height: 50,
width: 50,
},
text:{
marginVertical: 30,
fontSize: 25,
fontWeight: 'bold',
marginLeft: 30,
marginBottom: 5
},
});
export default Settings;
change loadingIndicatorSource={ item.image } to source={ item.image }

React native - Flatlist onPress is returning all the dataset not only the one selected

I am trying to use the Flatlist component to show some registers and select some multiple registers.
<FlatList
horizontal
bounces={false}
key={ingredientList.id}
data={ingredientList}
renderItem={({ item }) => (
<Card key={item.id} onPress={selectedIngredient(item)}>
<Text key={item.title} style={styles.titleText}>{item.name}</Text>
<ImageBackground key={item.illustration} source={item.illustration} style={styles.cardImage}></ImageBackground>
</Card>
)
}
keyExtractor={(item) => item.index}
/>
function selectedIngredient(item) {
console.log('selecionado: ' + item.name)
}
How can I do to get only the details about the Card I selected?
this is what the "ingredientList" return:
Array [
Object {
"id": 8,
"name": "leite condensado",
},
Object {
"id": 9,
"name": "creme de leite",
},
You can use TouchableOpacity for the click event.
Snapshot:
Here is the working example of how you can implement it:
import React, { useState } from 'react';
import {
Text,
View,
StyleSheet,
FlatList,
TouchableOpacity,
} from 'react-native';
import Constants from 'expo-constants';
// You can import from local files
// or any pure javascript modules available in npm
const ingredientList = [
{
id: 1,
name: 'item1',
},
{
id: 2,
name: 'item 2',
},
{
id: 3,
name: 'item 3',
},
{
id: 8,
name: 'item 4',
},
{
id: 4,
name: 'item 5',
},
{
id: 5,
name: 'item 6',
},
];
export default function App() {
const [selectedItem, setSelectedItem] = useState(null);
const selectedIngredient = (item) => {
console.log('selecionado: ' + item.name);
setSelectedItem(item);
};
return (
<View style={styles.container}>
<FlatList
style={styles.flatlist}
horizontal
bounces={false}
key={ingredientList.id}
data={ingredientList}
renderItem={({ item }) => (
<TouchableOpacity
style={styles.flatListItem}
key={item.id}
onPress={() => selectedIngredient(item)}>
<Text>{item.name}</Text>
</TouchableOpacity>
)}
keyExtractor={(item) => item.index}
/>
{selectedItem ? (
<View style={styles.selectedTextView}>
<Text style={styles.selectedText}>{`${selectedItem.name} selected`}</Text>
</View>
) : (
<View style={styles.selectedTextView}>
<Text style={styles.selectedText}>{`Nothing selected`}</Text>
</View>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
flatListItem: {
width: 100,
height: 100,
backgroundColor: 'white',
margin: 5,
borderRadius: 10,
justifyContent: 'center',
alignItems: 'center',
},
selectedTextView: {
flex: 1,
backgroundColor: 'white',
margin: 5,
borderRadius: 10,
justifyContent: 'center',
alignItems: 'center',
fontSize: 20
},
selectedText: {
fontSize: 30
},
});
Working Demo: Expo Snack
Try this const selectedIngredient = (item) => { console.log(item); }
and
<Card key={item.id} onPress={() => selectedIngredient(item)}>

How to use PanResponder inside horizontal FlatList

I want to drag out the selected item from the horizontal FlatList and drop it to another area of the screen. The problem is that my FlatList wrapper must have a fixed height and when trying to pull out selected element out FlatList component overflows it and my element gets hidden.
I have tried to change zIndex and set overflow to visible but it does not work properly because setting zIndex works with siblings only and pretty buggy just yet, overflow:visible did not affect layout at all.
Here is the screenshot:
Here is my code:
import React from 'react';
import {
SafeAreaView,
View,
FlatList,
Text,
StyleSheet,
Animated,
PanResponder
} from 'react-native';
import { v4 } from 'uuid';
export default class App extends React.PureComponent{
state = {
data: [
{ id: v4(), title: 'Lightcoral', hex: '#eb7474' },
{ id: v4(), title: 'Orchid', hex: '#eb74dc' },
{ id: v4(), title: 'Mediumpurple', hex: '#9a74eb' },
{ id: v4(), title: 'Mediumslateblue', hex: '#8274eb' },
{ id: v4(), title: 'Skyblue', hex: '#74b6eb' },
{ id: v4(), title: 'Paleturquoise', hex: '#93ece2' },
{ id: v4(), title: 'Palegreen', hex: '#93ecb6' },
{ id: v4(), title: 'Khaki', hex: '#d3ec93' }
]
}
_position = new Animated.ValueXY()
_panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: (event, gesture) => {
this._position.setValue({ x: gesture.dx, y: gesture.dy})
},
onPanResponderRelease: () => {}
})
_keyExtractor = (item) => item.id;
_renderItem = ({item}) => {
return (
<Animated.View
style={this._position.getLayout()}
{...this._panResponder.panHandlers}
>
<View style={[styles.itemBox, {backgroundColor: `${item.hex}`}]}>
<Text>{item.title}</Text>
</View>
</Animated.View>
)
}
render() {
const { data } = this.state
return (
<SafeAreaView style={styles.safeArea}>
<View style={styles.container}>
<View style={styles.targetArea}>
<Text>Drop HERE!!!</Text>
</View>
<View style={{ height: 80, borderColor: 'black', borderWidth: 2 }}>
<FlatList
data={data}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
horizontal={true}
/>
</View>
</View>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
safeArea: {
flex: 1
},
container: {
flex: 1,
justifyContent: 'space-between',
alignItems: 'center',
backgroundColor: '#fff',
},
itemBox: {
width: 80,
height: 80,
alignItems: 'center',
justifyContent: 'center',
borderWidth: 1,
borderColor: '#fff'
},
targetArea: {
height: 150,
width: 150,
alignItems: 'center',
justifyContent: 'center',
borderWidth: 1,
borderColor: '#eee',
backgroundColor: '#F5FCFF',
marginTop: 40
}
});
I want to move the selected item of flatList around the screen and put it on top of any other element of the screen, if i simply could programmatically set zIndex of each element - I would be over the moon but unfortunately it seems not working as simple as that. Please help me I very desperate(((
set overflow to visible in FlatList style.

How to handle Drag'n Drop gesture on horizontal FlatList with fixed height

I am trying to implement a Drag'n Drop functionality in my React Native application. I have already made a pretty good study of Gesture Responder System and PanResponder in particular as well as an Animated class, but I can not come up with a proper solution around connecting them with FlatList component.
The problem is that when I am trying to shift a Responder item beyond the scope of the View component wrapping FlatList (height: 80) it is visually getting hidden and parent Component obviously overlaps it..
Here is the screenShot: http://joxi.ru/82Q0dn1CwwE1Vm
Here is my code:
import React from 'react';
import {
SafeAreaView,
View,
FlatList,
Text,
StyleSheet,
Animated,
PanResponder
} from 'react-native';
import { v4 } from 'uuid';
export default class App extends React.PureComponent{
state = {
data: [
{ id: v4(), title: 'Lightcoral', hex: '#eb7474' },
{ id: v4(), title: 'Orchid', hex: '#eb74dc' },
{ id: v4(), title: 'Mediumpurple', hex: '#9a74eb' },
{ id: v4(), title: 'Mediumslateblue', hex: '#8274eb' },
{ id: v4(), title: 'Skyblue', hex: '#74b6eb' },
{ id: v4(), title: 'Paleturquoise', hex: '#93ece2' },
{ id: v4(), title: 'Palegreen', hex: '#93ecb6' },
{ id: v4(), title: 'Khaki', hex: '#d3ec93' }
]
}
_position = new Animated.ValueXY()
_panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: (event, gesture) => {
this._position.setValue({ x: gesture.dx, y: gesture.dy})
},
onPanResponderRelease: () => {}
})
_keyExtractor = (item) => item.id;
_renderItem = ({item}) => {
return (
<Animated.View
style={this._position.getLayout()}
{...this._panResponder.panHandlers}
>
<View style={[styles.itemBox, {backgroundColor: `${item.hex}`}]}>
<Text>{item.title}</Text>
</View>
</Animated.View>
)
}
render() {
const { data } = this.state
return (
<SafeAreaView style={styles.safeArea}>
<View style={styles.container}>
<View style={styles.targetArea}>
<Text>Drop HERE!!!</Text>
</View>
<View style={{ height: 80, borderColor: 'black', borderWidth: 2 }}>
<FlatList
data={data}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
horizontal={true}
/>
</View>
</View>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
safeArea: {
flex: 1
},
container: {
flex: 1,
justifyContent: 'space-between',
alignItems: 'center',
backgroundColor: '#fff',
},
itemBox: {
width: 80,
height: 80,
alignItems: 'center',
justifyContent: 'center',
borderWidth: 1,
borderColor: '#fff'
},
targetArea: {
height: 150,
width: 150,
alignItems: 'center',
justifyContent: 'center',
borderWidth: 1,
borderColor: '#eee',
backgroundColor: '#F5FCFF',
marginTop: 40
}
});
How can I change the location of the particular item of the FlatList, which is in a horizontal mode and has a fixed height, and move it to another area of the screen??
Please help me to knock that one out, every advice is much appreciated!