When adding horizontal={true} to my scrollview, I thought that would be enough to be able to scroll sideways. For some reason, even though there is enough content to scroll to, the images will not scroll continuously. If you copy and paste this code into snack.expo.io you will see what I mean.
I am not sure what is causing this issue, as I know the normal scrollview vertically works fine and scrolls like normal. I have also tried using nestedScrollenabled to true
Any insight at all is appreciated more than you know!
import React, { useState } from 'react';
import {Pressable, StyleSheet, Text, View, useWindowDimensions, Dimensions, Image, Animated, PanResponder,
TouchableOpacity, ScrollView, ImageBackground, Platform} from 'react-native';
import { SearchBar } from 'react-native-elements';
import {
scale,
verticalScale,
moderateScale,
ScaledSheet,
} from 'react-native-size-matters';
import { MaterialCommunityIcons } from '#expo/vector-icons';
const Images = [
{ id: '1', uri: require('./assets/snack-icon.png'), text: 'Test' },
{ id: '2', uri: require('./assets/snack-icon.png') /*text: "Test"*/ },
{ id: '3', uri: require('./assets/snack-icon.png') /*text: "Test"*/ },
{ id: '4', uri: require('./assets/snack-icon.png') /*text: "Test"*/ },
]
const pressableTest = () => {
let textlog = '';
const [state, setState] = useState(0);
};
export default class Home extends React.Component {
renderImagesHorizontal = () => {
return Images.map((item, i) => {
return (
<View
style={{
width : '150%',
paddingLeft: scale(10),
paddingRight: scale(10),
paddingBottom: scale(15),
}}>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('VenueDetails')}>
<ImageBackground
source={item.uri}
style={{
width: '100%',
height: scale(225),
shadowColor: '#000',
shadowOffset: { width: 1, height: 4 },
shadowOpacity: 1,
}}
imageStyle={{ borderRadius: 10 }}>
<View
style={{
position: 'absolute',
bottom: 10,
left: 10,
justifyContent: 'flex-start',
alignItems: 'flex-start',
}}>
<Text style={styles.name}>Name</Text>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<Text style={styles.category}>Category</Text>
<Text style={styles.dot}>⬤</Text>
<Text style={styles.money}>$$</Text>
<Text style={styles.dot}>⬤</Text>
<Text style={styles.starRating}>★★★</Text>
</View>
</View>
</ImageBackground>
</TouchableOpacity>
</View>
);
});
};
renderImagesVertical = () => {
return Images.map((item, i) => {
return (
<View style={{ paddingLeft: scale(10), paddingRight: scale(10), paddingBottom: scale(20) }}>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('VenueDetails')}>
<ImageBackground
source={item.uri}
style={{ width:'100%', height: scale(125),
shadowColor: '#000',
shadowOffset: {width: 1, height: 7},
shadowOpacity: 1,}} imageStyle = {{ borderRadius: 20}}>
<View
style={{
position: 'absolute',
bottom: 10,
left: 10,
justifyContent: 'flex-start',
alignItems: 'flex-start',
}}>
<Text style={styles.name}>Name</Text>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<Text style={styles.category}>Category</Text>
<Text style={styles.dot}>⬤</Text>
<Text style={styles.money}>$$</Text>
<Text style={styles.dot}>⬤</Text>
<Text style={styles.starRating}>★★★</Text>
</View>
</View>
</ImageBackground>
</TouchableOpacity>
</View>
);
});
};
state = {
search: '',
};
updateSearch = (search) => {
this.setState({ search });
};
render() {
const { search } = this.state;
return (
<ScrollView style={{ flex: 1, backgroundColor: '#272933', horizontal: 'true' }}>
<View style={{flexDirection:'row', marginTop: scale(20)}}>
{/*this will proabbly say somethign different and probably have a different look to it but you get the idea
I was also trying to add a shadow to this but couldnt figure it out. */}
<Text style={{marginTop: scale(30) ,fontSize: scale(40), fontWeight: 'bold', color: '#FFFFFF', paddingLeft: scale(20)}}>
Home
</Text>
<View style={{paddingTop: scale(40), paddingLeft: scale(155)}}>
</View>
</View>
<SearchBar
placeholder="Search..."
onChangeText={this.updateSearch}
value={search}
round='true'
containerStyle={{backgroundColor: '#272933', borderBottomColor: 'transparent', borderTopColor: 'transparent',
paddingLeft: scale(20) , paddingRight: scale(20)}}
inputContainerStyle={{height: scale(30), width: scale(310), backgroundColor: '#3A3B3C'}}
searchIcon={() => <MaterialCommunityIcons name="glass-mug-variant" size={25} color='#87909A'/>}
clearIcon= 'null'
/>
<ScrollView
horizontal={true}
>
<View style={{ flex: 1, flexDirection : 'row', marginTop: 15 }}>{this.renderImagesHorizontal()}</View>
</ScrollView>
<View style={{ flex: 1, marginTop: 15 }}>{this.renderImagesVertical()}</View>
</ScrollView>
);
}
}
const styles = ScaledSheet.create({
starRating: {
color: 'white',
fontSize: '20#s',
textShadowOffset: { width: 2, height: 2 },
textShadowRadius: 2,
textShadowColor: '#000',
},
category: {
color: 'white',
fontSize: '20#s',
textShadowOffset: { width: 2, height: 2 },
textShadowRadius: 2,
textShadowColor: '#000',
},
name: {
fontWeight: 'bold',
color: 'white',
fontSize: '25#s',
textShadowOffset: { width: 2, height: 2 },
textShadowRadius: 2,
textShadowColor: '#000',
},
dot: {
color: 'white',
fontSize: '5#s',
paddingLeft: '5#s',
paddingRight: '5#s',
textShadowOffset: { width: 2, height: 2 },
textShadowRadius: 2,
textShadowColor: '#000',
},
money: {
color: 'white',
fontSize: '20#s',
},
});
in android you must add nestedScrollEnabled={true} to Enables nested scrolling for Android API level 21+. see here
<ScrollView>
<ScrollView nestedScrollEnabled={true}>
</ScrollView>
</ScrollView>
try snack here (test in android & ios not web)
Related
I need to make a screen like you see below in React Native
like that
I need to list this screen with this datalist I have
let denemeData = [
{
id: 1,
BestSellers: [
{
id: 1,
SellerName: 'Steril Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1254788325/photo/forget-sweet-try-home-sanitised-home.jpg?s=612x612&w=0&k=20&c=q6t80qrWvnWRln4PoxF8giI0hr9cNqdvFQiooFqIK3M=',
},
{
id: 2,
SellerName: 'Işıltı Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1218727916/photo/woman-wearing-gloves-cleaning-desktop.jpg?s=612x612&w=0&k=20&c=i0DvmRBBjo-Q4DaJHywi4mQzRYOCRjPKh3m7wIYHHNw=',
},
{
id: 3,
SellerName: 'Aybars Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1358089804/photo/beautiful-smiling-young-woman-cleaning-and-wiping-window-with-spray-bottle-and-rag-stock-photo.jpg?s=612x612&w=0&k=20&c=1OCBbZeIxBHAsrm6K7FTXgST91xb9TCaHYc74y1bq8s=',
},
{
id: 4,
SellerName: 'Hizmet Kolay',
imageUrl:
'https://media.gettyimages.com/id/1055221704/photo/young-woman-washing-window.jpg?s=612x612&w=0&k=20&c=Nd2TDn8pTRPe_bEkGec7ICNQ3pcoksMQWTCcGRVpfQI=',
},
{
id: 5,
SellerName: 'Aybars Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1358089804/photo/beautiful-smiling-young-woman-cleaning-and-wiping-window-with-spray-bottle-and-rag-stock-photo.jpg?s=612x612&w=0&k=20&c=1OCBbZeIxBHAsrm6K7FTXgST91xb9TCaHYc74y1bq8s=',
},
{
id: 6,
SellerName: 'Hizmet Kolay',
imageUrl:
'https://media.gettyimages.com/id/1055221704/photo/young-woman-washing-window.jpg?s=612x612&w=0&k=20&c=Nd2TDn8pTRPe_bEkGec7ICNQ3pcoksMQWTCcGRVpfQI=',
},
],
},
];`
I couldn't figure out how to list with FlatList as in the image because as it can be seen in the image, I need to make the first data large, the second and third data small and side by side, I tried to play with numColumns, I tried to play with numColumns, I tried to adjust the View manually, I couldn't do it in any way and my brain stopped, please guide me, I'm very tired and I can't do it, my brain stopped.
Thanks for ur helps
I tried giving numColumns value with FlatList, but I did not get the result I expected.;
<FlatList
bounces={false}
numColumns={2}
scrollEnabled={true}
data={sellers}
renderItem={({item}) => (
<Pressable
onPress={() => {
denemeFunc(item);
}}
style={{
height: 170,
width: '47%',
borderRadius: 10,
backgroundColor: 'red',
margin: 5,
}}>
<Image
style={{
height: '100%',
resizeMode: 'cover',
width: '100%',
borderRadius: 10,
position: 'absolute',
}}
source={{
uri: item.imageUrl,
}}
/>
<View
style={{
padding: 8,
justifyContent: 'flex-end',
alignItems: 'center',
height: '100%',
position: 'absolute',
}}>
<Text
style={{
color: 'white',
fontSize: 16,
fontFamily: 'Poppins-Bold',
textAlign: 'center',
}}>
{item.SellerName}
</Text>
</View>
</Pressable>
)}
showsVerticalScrollIndicator={false}
/>
as I can see in your layout, for the even lines you want a component with just one line and for odd lines you want a component with two images. So you can render different components according to the index of the list.
I think you can do something like this:
<FlatList
bounces={false}
numColumns={2}
scrollEnabled={true}
data={sellers}
renderItem={({item, index}) => (
if(index% 2 === 0){
// You render a component with just one line.
} else {
// You create the component with columns - A component with a
//flexDirection: 'row'...
}
)}
showsVerticalScrollIndicator={false}
/>
Hope this answer helps you :).
Use VirtualizedList for more flexibility and render items by row. Here is the simplified version.
Calculate row count based on the layout
Return array of items for a certain row based on the layout
Render items for the row
Optional: Add padding to the last item to compensate the partial row
const isOdd = (index) => index % 2 !== 0
// 1.
const getRowCount = (items) => items.length - Math.floor(items.length / 3)
// 2.
const getRow = (items, index) =>
isOdd(index)
? items.slice(index + (index / 2), index + (index / 2) + 2)
: [items[2 * index - index / 2]]
const requiresPadding = (items, index, row) =>
row.length == 1 && getRowCount(items) - 1 === index && isOdd(index)
...
<VirtualizedList
data={items}
getItemCount={getRowCount}
getItem={getRow}
renderItem={({ item: row, index }) => (
<View style={{ flexDirection: 'row' }}>
// 3.
{row.map((i) => <Item title={i.title}/>)}
// 4.
{requiresPadding(items, index, row) && <PaddingItem/>}
</View>
)}
keyExtractor={(row) => row[0].id}
/>
...
const Item = ({ title }) => (
<View style={{
flex: 1,
backgroundColor: '#eee',
height: 150,
justifyContent: 'center',
alignItems: 'center',
margin: 8,
}}>
<Text>{title}</Text>
</View>
);
const PaddingItem = () => (
<View style={{flex: 1, margin: 8}}/>
)
may be this will help you!
App.js
import React from 'react';
import {
SafeAreaView,
View,
FlatList,
StyleSheet,
ImageBackground,
Text,
StatusBar,
} from 'react-native';
const DATA = [
{
id: 1,
SellerName: 'Steril Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1254788325/photo/forget-sweet-try-home-sanitised-home.jpg?s=612x612&w=0&k=20&c=q6t80qrWvnWRln4PoxF8giI0hr9cNqdvFQiooFqIK3M=',
},
{
id: 2,
SellerName: 'Işıltı Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1218727916/photo/woman-wearing-gloves-cleaning-desktop.jpg?s=612x612&w=0&k=20&c=i0DvmRBBjo-Q4DaJHywi4mQzRYOCRjPKh3m7wIYHHNw=',
},
{
id: 3,
SellerName: 'Aybars Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1358089804/photo/beautiful-smiling-young-woman-cleaning-and-wiping-window-with-spray-bottle-and-rag-stock-photo.jpg?s=612x612&w=0&k=20&c=1OCBbZeIxBHAsrm6K7FTXgST91xb9TCaHYc74y1bq8s=',
},
{
id: 4,
SellerName: 'Hizmet Kolay',
imageUrl:
'https://media.gettyimages.com/id/1055221704/photo/young-woman-washing-window.jpg?s=612x612&w=0&k=20&c=Nd2TDn8pTRPe_bEkGec7ICNQ3pcoksMQWTCcGRVpfQI=',
},
{
id: 5,
SellerName: 'Aybars Temizlik',
imageUrl:
'https://media.gettyimages.com/id/1358089804/photo/beautiful-smiling-young-woman-cleaning-and-wiping-window-with-spray-bottle-and-rag-stock-photo.jpg?s=612x612&w=0&k=20&c=1OCBbZeIxBHAsrm6K7FTXgST91xb9TCaHYc74y1bq8s=',
},
{
id: 6,
SellerName: 'Hizmet Kolay',
imageUrl:
'https://media.gettyimages.com/id/1055221704/photo/young-woman-washing-window.jpg?s=612x612&w=0&k=20&c=Nd2TDn8pTRPe_bEkGec7ICNQ3pcoksMQWTCcGRVpfQI=',
},
];
const renderItem = ({ item }) => (
<>
<View>
{item.id == 1 && (
<View
style={{
margin: 10,
height: 120,
}}>
<ImageBackground
source={item.imageUrl}
style={{ width: '100%', height: '100%', borderRadius: 20 }}>
<Text style={{ color: '#fff', fontSize: 20, fontWeight: 'bold' }}>
{item.SellerName}
</Text>
</ImageBackground>
</View>
)}
{item.id == 2 ? (
<>
<View
style={{
flexDirection: 'row',
margin: 10,
height: 120,
width: 100,
justifyContent: 'space-between',
}}>
<View>
<ImageBackground
source={item.imageUrl}
style={{ width:150, height: '100%', borderRadius: 20 ,margin:5}}>
<Text
style={{ color: '#fff', fontSize: 20, fontWeight: 'bold' }}>
{item.SellerName}
</Text>
</ImageBackground>
</View>
<View>
<ImageBackground
source={item.imageUrl}
style={{ width:150, height: '100%', borderRadius: 20 ,margin:5}}>
<Text
style={{ color: '#fff', fontSize: 20, fontWeight: 'bold' }}>
{item.SellerName}
</Text>
</ImageBackground>
</View>
</View>
</>
) : null}
{item.id == 3 && (
<View
style={{
margin: 10,
height: 120,
}}>
<ImageBackground
source={item.imageUrl}
style={{ width: '100%', height: '100%', borderRadius: 20 }}>
<Text style={{ color: '#fff', fontSize: 20, fontWeight: 'bold' }}>
{item.SellerName}
</Text>
</ImageBackground>
</View>
)}
{item.id == 4 ? (
<>
<View
style={{
flexDirection: 'row',
margin: 10,
height: 120,
width: 100,
justifyContent: 'space-between',
}}>
<View>
<ImageBackground
source={item.imageUrl}
style={{ width:150, height: '100%', borderRadius: 20 ,margin:5}}>
<Text
style={{ color: '#fff', fontSize: 20, fontWeight: 'bold' }}>
{item.SellerName}
</Text>
</ImageBackground>
</View>
<View>
<ImageBackground
source={item.imageUrl}
style={{ width:150, height: '100%', borderRadius: 20 ,margin:5}}>
<Text
style={{ color: '#fff', fontSize: 20, fontWeight: 'bold' }}>
{item.SellerName}
</Text>
</ImageBackground>
</View>
</View>
</>
) : null}
</View>
</>
);
const App = () => {
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight || 0,
},
});
export default App;
here is output:
Here's the UI I want to create:
How do I create the above UI in react native and have it scale on all devices? I tried using flexbox but I couldn't get the boxes to be squares. The code below is using fixed width and height in which I was thinking I could scale them in proportion to the flex container they're in but I don't know how that would be implemented and I haven't found anything similar so far.
return (
<View>
<View style={styles.cardContainer}>
<View style={styles.leftSection}></View>
<View style={styles.rightSection}>
<View style={styles.section}>
<View style={styles.smallSquare}></View>
<View style={styles.smallSquare}></View>
<View style={styles.smallSquare}></View>
</View>
<View style={styles.section}>
<View style={styles.smallSquare}></View>
<View style={styles.smallSquare}></View>
<View style={styles.smallSquare}></View>
</View>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
cardContainer: {
height: 152,
flexDirection: "row",
borderRadius: 26,
marginTop: 8,
padding: 5,
backgroundColor: "lightgrey",
justifyContent: "space-between",
},
leftSection: {
flex: 3,
backgroundColor: "teal",
borderRadius: 23,
},
rightSection: {
flex: 5,
marginHorizontal: 10,
},
largeSquare: {
width: "100%",
height: "100%",
borderRadius: 23,
},
section: {
flex: 1,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
},
smallSquare: {
backgroundColor: "teal",
borderRadius: 14,
width: 62,
height: 62,
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.5.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.5.0/umd/react-dom.production.min.js"></script>
I just made the code for you. Just copy and play with it.
import React from "react";
import { FlatList, StyleSheet, Text, View } from "react-native";
const DATA = [1, 2, 3, 4, 5, 6];
const renderItem = ({ item }) => {
return <View style={styles.item}></View>;
};
function App() {
return (
<View style={styles.app}>
<View style={styles.letConatiner} />
<View style={{ flex: 2.5 }}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={(item) => item}
numColumns={3}
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
app: {
flex: 1,
flexDirection: "row",
flexWrap: "wrap",
backgroundColor: "lightgrey",
padding: 10
},
letConatiner: {
height: "62%",
flex: 1,
backgroundColor: "teal",
borderRadius: 15,
marginTop: 10
},
item: {
flex: 1,
padding: 50,
backgroundColor: "green",
margin: 10,
borderRadius: 15,
height: "50%"
}
});
export default App;
Not the perfect solution I was hoping to find but it's a start. Maybe someone can build on it.
import { StatusBar } from "expo-status-bar";
import {
StyleSheet,
View,
Text,
Image,
Pressable,
FlatList,
Dimensions,
} from "react-native";
const windowWidth = Dimensions.get("window").width;
const windowHeight = Dimensions.get("window").height;
export default function HomeScreen() {
return (
<View style={styles.homeScreen}>
<View style={styles.cardOuter}>
<View style={styles.cardContainer}>
<View style={styles.leftSection}>
<View style={styles.bigThumbnail}></View>
</View>
<View style={styles.rightSection}>
<View style={styles.section}>
<View style={styles.smallThumbnail}></View>
<View style={styles.smallThumbnail}></View>
<View style={styles.smallThumbnail}></View>
</View>
<View style={styles.section}>
<View style={styles.smallThumbnail}></View>
<View style={styles.smallThumbnail}></View>
<View style={styles.smallThumbnail}></View>
</View>
</View>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
homeScreen: {
backgroundColor: "black",
flex: 1,
paddingHorizontal: 10,
},
cardOuter: {
paddingVertical: 4,
backgroundColor: "#eee",
borderRadius: 26,
},
cardContainer: {
height: windowHeight / 5.4,
flexDirection: "row",
borderRadius: 26,
paddingHorizontal: 10,
justifyContent: "center",
alignItems: "center",
},
leftSection: {
marginRight: 0,
},
rightSection: {
flex: 5,
},
bigThumbnail: {
backgroundColor: "teal",
borderRadius: 26,
width: windowWidth / 3,
height: "96%",
},
smallThumbnail: {
backgroundColor: "teal",
borderRadius: 14,
width: windowWidth / 6,
height: windowWidth / 6,
},
section: {
flex: 1,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingLeft: 10,
marginVertical: 0,
},
});
I'm having a problem to stretch the text input fully till the whole "item.membername" comes into a row like created UI. Currently the "item.membername" goes to second line because of a long string membername. Please do help me out. Below I have attached the UI pictures along with code.
Created UI:
Current UI:
ApprovedScreen.js
import React, {useState} from 'react';
import {GrayCustomView} from './../components/styles';
import {View, Text, TouchableOpacity, Image, FlatList} from 'react-native';
import GlobalStyle from '../components/GlobalStyle';
import {ApprovedReceiptData} from '../constants/dummy'
import { useNavigation } from '#react-navigation/native';
const ApprovedReceiptScreen = () => {
const navigation = useNavigation();
const renderItem = ({item}) => (
<GrayCustomView>
{item.membername === 'No Receipt History' ? (
<TouchableOpacity style={[GlobalStyle.ApprovedButtonContainer]}>
<View style={[GlobalStyle.ReceiptUpperContainer]}>
<Text style={[GlobalStyle.ReceiptDetails5]}>{item.membername}</Text>
</View>
</TouchableOpacity>
) : (
<TouchableOpacity style={[GlobalStyle.ApprovedButtonContainer]} activeOpacity={0.8} onPress={() => {navigation.navigate('ReceiptDetailsScreen',{migrateData: item});}}>
<View style={[GlobalStyle.LeftContainer]}>
<View style={[GlobalStyle.UpperContainer]}>
<View style={[GlobalStyle.ReceiptHeader]}>
<Text style={[GlobalStyle.ReceiptListTitle]}>{item.receiptnum}</Text>
</View>
</View>
<View style={[GlobalStyle.LowerLeftContainer]}>
<View style={[GlobalStyle.ReceiptImageView]}>
<Image style={[GlobalStyle.ReceiptImageList]} source={{uri: item.memberImage}}/>
</View>
<View style={[GlobalStyle.LowerRightContainer]}>
<Text style={[GlobalStyle.ReceiptDetails1]}>{item.membername}</Text>
<Text style={[GlobalStyle.ReceiptDetails1]}>{item.date}</Text>
</View>
</View>
</View>
<View style={[GlobalStyle.RightContainer]}>
<View style={[GlobalStyle.RightUpperContainer]}>
<Text style={[GlobalStyle.ReceiptListTitle1]}>{item.points}</Text>
</View>
<View style={[GlobalStyle.RightLowerContainer]}>
<Text style={[GlobalStyle.ReceiptDetails4]}>{item.receiptamount}</Text>
</View>
</View>
</TouchableOpacity>
)}
</GrayCustomView>
)
Globalstyle.js
ApprovedButtonContainer:{
width: DEVICE_WIDTH * 0.86,
height: DEVICE_HEIGHT * 0.20,
backgroundColor: white,
elevation: 11,
marginLeft: 30,
borderRadius: 6,
marginBottom: 10,
marginTop: 20,
flexDirection: 'row'
},
LeftContainer:{
flex: 2
},
UpperContainer:{
flex: 1,
justifyContent: 'center',
paddingHorizontal: 5,
},
ReceiptImageList:{
width: DEVICE_WIDTH * 0.15,
height: DEVICE_HEIGHT * 0.09,
backgroundColor: empty,
borderRadius: 6,
marginTop: 10,
marginLeft: 5
},
LowerLeftContainer:{
flex: 2,
flexDirection: 'row',
},
ReceiptImageView:{
flex: 1,
padding: 5
},
LowerRightContainer:{
flex: 2,
justifyContent: 'center',
paddingHorizontal: 5,
},
ReceiptDetails1:{
color: black,
fontSize: 14,
fontWeight: 'normal',
backgroundColor: empty,
},
RightContainer:{
flex: 1,
},
RightUpperContainer:{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
ReceiptListTitle1:{
color: black,
fontWeight: 'bold',
fontSize: 17
},
RightLowerContainer:{
flex: 2,
alignItems: 'center',
justifyContent: 'center',
},
ReceiptDetails4:{
color: black,
fontSize: 22,
fontWeight: 'bold',
},
ReceiptListTitle:{
color: black,
fontSize: 17,
fontWeight: 'bold',
},
})
its my first time i create an APP for my study project , i created app of database of movies using TMDB API , and it remain one last step to finish my project , and it's creating WatchList or Plan to Watch , and i have no idea how to make it . please can someone who have idea of how to create it with Async Storage or anything to save watchlist, and where to add it?
I will put my code
this code of Movie screen, and i need a touchableopacity that make save the movie into favorite component
import React, {useEffect, useState} from 'react';
import {
View,
Text,
Image,
Dimensions,
StyleSheet,
Linking,
ImageBackground,
TouchableOpacity,
ScrollView,
FlatList
} from 'react-native';
import {IMAGE_POSTER_URL} from '../config';
import {GET} from '../../Services/API';
import Loader from '../Components/Loader';
import Constants from '../Components/Constants';
import TrendingMovies from '../Components/TrendingMovies';
import TrendingPeople from '../Components/TrendingPeople';
import { createStackNavigator } from "#react-navigation/stack";
import PeopleDetails from '../Components/PeopleDetails.js';
import { LinearGradient } from 'expo-linear-gradient';
import {POSTER_IMAGE} from '../config';
import AsyncStorage from '#react-native-async-storage/async-storage';
const deviceHeight = Dimensions.get('window').height;
const deviceWidth = Dimensions.get('window').width;
const MovieDetails = props => {
const [loading, setLoading] = useState(true);
const [details, setDetails] = useState();
const [favourites, setFavourites] = useState([]);
useEffect(() => {
const getDetails = async () => {
const data = await GET(`/movie/${props.route.params.movieId}`);
setDetails(data);
setLoading(false);
};
getDetails();
}, []);
useEffect(() => {
const getVideo = async () => {
const results = await GET(`/movie/${props.route.params.movieId/videos}`);
setDetails(results);
setLoading(false);
};
getVideo();
}, []);
const getGenre = () => {
return details.genres.map(genre => (
<View >
<Text style={styles.genre}>{genre.name}</Text>
</View>
));
};
return (
<View style={styles.sectionBg}>
{loading ? (
<Loader />
) : (
<View style={{ flex: 1 }} >
<Image
source={{uri: `${IMAGE_POSTER_URL}${details.backdrop_path}`}}
style={styles.imageBg}
/>
<View style={{flexDirection:'row', justifyContent:'space-between', alignItems:'center', marginRight:15, marginTop:10}}>
<TouchableOpacity onPress={() => props.navigation.goBack()}
style={{ marginLeft:20, marginTop: 20, marginBottom:20}}
>
<Image
source={require("../../assets/icons/back.png")}
style={{ width:93/1.4 , height: 50/1.4 }} />
</TouchableOpacity>
<TouchableOpacity
style={{ marginLeft:20, marginTop: 20, marginBottom:20}}
>
<Image
source={require("../../assets/icons/nolicked.png")}
style={{ width:256/5.7 , height: 252/5.7 }} />
</TouchableOpacity>
</View>
<ScrollView style={{ flex:1 ,}} >
<TouchableOpacity onPress={() => {
Linking.openURL('https://www.youtube.com/watch?v=${details.key}');
}}
style={{ marginTop:240, marginLeft: "70%",zIndex:1 }}
>
<Image
source={require("../../assets/icons/youtube.png")}
style={{ width: 75, height: 75}} />
</TouchableOpacity>
<ImageBackground
source={require("../../assets/icons/hmm.png")}
style={{ width:'100%' , height: '84%',zIndex:-1 ,marginTop: -60,marginBottom:20}} >
<View style={{ alignSelf: 'center' , marginTop:40 }} >
<View style={{flexDirection: 'row' }} >
<Image
source={{uri: `${IMAGE_POSTER_URL}${details.poster_path}`}}
style={{ width: 150/1.2 , height: 220/1.2 , borderRadius: 20, marginTop: 40 , marginLeft: 20, zIndex:1 }} />
<View style= {{flexDirection:'column' , }} >
<Text style={styles.detailsMovieTitle}>{details.title}</Text>
<View style={{flexDirection: 'row' , alignItems: 'center', marginLeft: 15 , backgroundColor:'orange' , width:70, marginVertical: 5, borderRadius:10}} >
<Image
source={require("../../assets/icons/star.png")}
style={{ width: 20, height: 20 , marginLeft: 5, marginVertical:8}} />
<Text style= {{color:'#20222A' , fontSize: 18, marginLeft: 6, fontWeight:'bold' ,marginRight: 15}} >{details.vote_average}</Text>
</View>
<View style={{ flexDirection: 'row', width: 80 ,marginTop:25, marginLeft:20}}>
{getGenre()}
</View>
<Text style={{marginLeft: 14,
marginHorizontal:-5,
marginVertical:5,
fontWeight:'bold',
color: '#C3C3C3',
fontSize: 10,}}>{details.runtime} Minutes</Text>
<Text style={{marginLeft: 14,
marginHorizontal:-5,
color: '#C3C3C3',
fontWeight:'bold',
fontSize: 10,}}> Release Date: {details.release_date} </Text>
</View>
</View>
<View style={{marginLeft:15, zIndex:1 , marginBottom:50, marginLeft:20}} >
<Text style={{color:'white', fontSize:16, fontWeight:'bold' , marginBottom: 1,marginLeft: -5}} > Overview </Text>
<Text style={{color: 'white',
fontSize: 12, width:330, marginBottom:15}}>{details.overview}</Text>
<TrendingPeople
title="Actors"
navigation={props.navigation}
url={`/movie/${props.route.params.movieId}/credits`}
isForPage="details"
/>
<View style={{marginLeft: -15, marginTop:10, }} >
<TrendingMovies
title="SIMILAR MOVIES"
navigation={props.navigation}
url={`/movie/${props.route.params.movieId}/similar`}
/>
</View>
</View>
</View>
</ImageBackground>
</ScrollView>
</View>
)}
</View>
);
};
const styles = StyleSheet.create({
sectionBg: {
backgroundColor: Constants.baseColor,
height: deviceHeight,
flex:1
},
trendingPeopleImage: {
height: 70,
width: 70,
borderRadius: 500,
},
trendingPeopleName: {
width: 60,
color: Constants.textColor,
fontSize: 12,
textAlign: 'center',
marginTop: 10,
},
trendingPeopleContainer: {
margin: 10,
},
heading: {
fontSize: 12,
color: 'white',
margin: 10,
fontWeight:'bold'
},
posterImage: {
height: 800,
width: 150,
borderRadius: 10,
},
movieTitle: {
color: Constants.textColor,
width: 150,
textAlign: 'center',
marginTop: 5,
fontSize: 20,
fontWeight:'bold'
},
imageBg: {
position: 'absolute', top:0, left:0 ,
width: deviceWidth,
height: 400,
opacity: 0.8
},
detailsMovieTitle: {
fontSize: 20,
width: 180,
fontWeight:'bold',
color: 'white',
marginLeft:15,
marginTop: 35
},
linkContainer: {
backgroundColor: Constants.secondaryColor,
borderRadius: 100,
padding: 10,
width: 45,
marginLeft: 20,
marginTop: -20,
},
overview: {
color: 'white',
marginHorizontal: 10,
textAlign: 'justify',
fontSize: 16,
},
details: {
color: 'white',
fontSize: 11,
marginLeft: 10,
fontWeight: 'bold',
},
detailsContainer: {
display: 'flex',
marginLeft:15
},
genreContainer: {
borderColor: Constants.textColor,
paddingHorizontal: 0,
},
genre: {
width: 50,
marginHorizontal:-5,
fontWeight:'bold',fontWeight:'bold',
color: '#C3C3C3',
marginRight:4,
fontSize: 9,
},
image : {
height: 100,
width: 180,
borderRadius: 15,
paddingHorizontal: 5,
marginTop: 10,
marginLeft: 20
},
Text: {
marginLeft: 20,
color: 'white',
fontWeight: 'bold',
fontSize: 20
},
title: {
marginTop: 10,
width: 150,
textAlign: 'center',
color: 'white',
fontWeight: 'bold',
fontSize: 12
}
});
export default MovieDetails;```
First you create a favorite state
const [ favorites, setFavorites ] = useState([]);
Then you use useEffect to load the favorite from async storage.
const getData = async () => {
try {
const value = await AsyncStorage.getItem('#storage_key')
if(value !== null) {
setFavorites(JSON.parse('#storage_key'));
}
} catch(e) {
// error reading value
}
}
useEffect(() => {
getData();
}, [])
Then you create a touchable component to add to favorites.
<TouchableOpacity onPress={() => addToFavorites('some_id')}>
Add to Favorites
</TouchableOpacity>
Create the add to favorite function
const addToFavorites = async (id) => {
await AsyncStorage.setItem('#storage_key', JSON.stringify([...favorites, id]))
setFavorites([...favorites, id]);
}
More on Asyncstorage usage here - https://react-native-async-storage.github.io/async-storage/docs/usage
Problem
I am creating an app with react native and firebase where users can post to firebase, and then my app will render all of the posts. When I added the code to render the posts from firebase (flatlist), nothing renders. I convert the list from firebase to an array, then use that array in a flatlist to render the posts, but nothing is showing up. I would love some help.
Code
import React, { Component } from 'react';
import { StyleSheet, Text, View, Image, TextInput, ScrollView, TouchableHighlight, Button, FlatList } from 'react-native';
import { Font } from 'expo';
import * as firebase from 'firebase';
const firebaseConfig = {
apiKey: "API_KEY",
authDomain: "candidtwo.firebaseapp.com",
databaseURL: "https://candidtwo.firebaseio.com",
storageBucket: "candidtwo.appspot.com",
};
const firebaseApp = firebase.initializeApp(firebaseConfig);
var fontLoaded = false;
var ref = firebase.database().ref('posts');
var newPostRef = ref.push();
var postWidth = 350;
export default class App extends React.Component {
state = {
fontLoaded: false,
};
componentDidMount() {
Expo.Font.loadAsync({
'JosefinSans-Regular.ttf': require('./JosefinSans-Regular.ttf'),
});
}
constructor(props) {
super(props);
this.state = { postInput: ""}
}
getItems() {
var items = [];
var query = ref.orderByKey();
query.once ('value', (snap) => {
snap.forEach ( (child) => {
items.push(childs.val());
});
});
return items;
}
renderItem({ items, index }) {
return <View>
<View style={{width: parseInt(this.state.postWidth), height: 250, backgroundColor: '#1daff1', alignItems: 'center', justifyContent: 'center', borderRadius: 10, paddingLeft: 10, paddingRight:10}}>
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', textAlign: 'center'}}>
{toString(reverse(items))}
</Text>
</View>
<View style={{width: parseInt(this.state.postWidth), height: 40, borderRadius: 10, backgroundColor: '#147aa8', flexDirection: 'row',paddingLeft:5}} >
<Image source={require('./CandidtwoImages/unlove.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
-
</Text>
<Image source={require('./CandidtwoImages/undislike.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
-
</Text>
<Image source={require('./CandidtwoImages/comments.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
-
</Text>
</View>
<View style={{width: 1, height: 6, backgroundColor: '#e8e8e8'}} />
</View>;
}
render() {
return (
<View style={styles.container}>
<View style={styles.button}>
<View style={{width: 1, height: 30, backgroundColor: '#e8e8e8'}} />
<Button
onPress={() => this.setState({ fontLoaded: true })}
title="Press Me To Load the App After 15 Seconds!"
color="#fe8200"
accessibilityLabel="Get started anonymously!"
/>
</View>
{this.state.fontLoaded ? (
<View style={styles.container}>
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 16 }}>
Whats on your mind? Create a post!
</Text>
<TextInput
style={{height:40, width: 320, borderColor: '#303030', borderWidth: 1}}
onChangeText={(postInput)=>this.setState({postInput})}
value={this.state.postInput}
/>
<Button
style={{justifyContent: 'center'}}
onPress={() => {
newPostRef.set({ content:this.state.postInput });
this.setState({ postInput: "Your post was succsesfully uploaded! :)" })
}}
title=" + "
color="#fe8200"
/>
<ScrollView>
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 16 }}>
Adjust the size of posts:
</Text>
<TextInput
style={{height:40, width: 100, borderColor: '#303030', borderWidth: 1}}
onChangeText={(postWidth)=>this.setState({postWidth})}
value={this.state.postWidth}
/>
<View style={{width: 1, height: 6, backgroundColor: '#e8e8e8'}} />
<View style={{width: parseInt(this.state.postWidth), height: 250, backgroundColor: '#1daff1', alignItems: 'center', justifyContent: 'center', borderRadius: 10, paddingLeft: 10, paddingRight:10}} >
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', textAlign: 'center'}}>
Why do android phones have higher inital quality than apple phones, but apple phones have a more consistent amount of quality throughout their years?
</Text>
</View>
<View style={{width: parseInt(this.state.postWidth), height: 40, borderRadius: 10, backgroundColor: '#147aa8', flexDirection: 'row',paddingLeft:5}} >
<Image source={require('./CandidtwoImages/unlove.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
3
</Text>
<Image source={require('./CandidtwoImages/undislike.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
1
</Text>
<Image source={require('./CandidtwoImages/comments.png')} />
<Text style={{ fontFamily: 'JosefinSans-Regular.ttf', fontSize: 22, color: '#ffffff', paddingRight: 5, paddingTop:5}}>
8
</Text>
</View>
<FlatList
data={this.getItems}
renderItem={this.renderItem}
/>
</ScrollView>
</View>) : (null) }
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 8,
backgroundColor: '#e8e8e8',
alignItems: 'center'
},
button: {
flex: 1,
backgroundColor: '#e8e8e8',
alignItems: 'center'
},
});
Picture of firebase database
id have getItems() in your componentWillMount method, and have it set a state ( Such as "firebaseItems" ) or such. Then in your FlatList have your data equal {this.state.firebaseItems}. This will force a re-render once you receive your information. EG
componentWillMount(){
this.getItems();
}
getItems(){
var items = [];
var query = ref.orderByKey();
query.once ('value', (snap) => {
snap.forEach ( (child) => {
items.push(childs.val());
});
}).then(() => {
this.setState({firebaseItems: items});
});
}
then later
<FlatList data = {this.state.firebaseItems}.../>