React native - Adapt horizontal ScrollView's height to its children - javascript

See the following snack
I need to adapt the height of the ScrollView to its children. It seems that ScrollView is using { flex: 1 } by default (not sure). Any ideas how to make it possible?
<View style={{ flex: 1 }}>
<ScrollView horizontal style={{ backgroundColor: 'red' }}>
<View
style={{ width: 60, height: 30, marginLeft: 5, backgroundColor: 'lime' }}
/>
</ScrollView>
<View style={{ flex: 1, backgroundColor: 'yellow' }} />
</View>
Thank you.
Note: Is it possible to do it without using { height: 30 } ?

Wrapping the ScrollView inside a View does the trick.
<View style={{ flex: 1 }}>
<View>
<ScrollView horizontal style={{ backgroundColor:"red" }}>
<View style={{ width: 60, height: 30, marginLeft: 5, backgroundColor: "lime" }} />
</ScrollView>
</View>
<View style={{ flex: 1, backgroundColor:"yellow" }} />
</View>

Related

TouchableOpacity takes more than half of width

I'm trying to arrange my cards into something like this
But heres what I got
As you can see the TouchableOpacity (yellow color) takes more than half of the container width (orange color).
I've tried may things by adding width: "50%" and set alignItems with flex-start, flex-end, etc but it only make things worse.
Here's my card component code
const SmallMateriCard = (props) => {
return (
<NativeBaseProvider >
<Box maxW={"70%"} alignItems="flex-start" style={{backgroundColor:"blue"}}>
{/* <Pressable onPress={props.onPress}> */}
<Box
borderRadius={18}
overflow="hidden"
style={{
width: "100%",
backgroundColor: 'white',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 0,
},
shadowOpacity: 0.1,
shadowRadius: 3,
elevation: 4,
}}>
<Box>
<AspectRatio w="100%" ratio={6/5} >
{props.cardIcon && (
<Image
borderRadius={18}
source={{uri: props.cardIcon}}
alt="image"
/>
)}
</AspectRatio>
</Box>
<Stack px="6" py="6" >
<Text
style={[
font.family.extrabold,
{ fontSize: 15, color: color.primary },
]}>
{props.title}
</Text>
</Stack>
</Box>
{/* </Pressable> */}
</Box>
</NativeBaseProvider>
);
};
export default SmallMateriCard;
and here's my screen code
const UKKSekunderScreen = ({ navigation }) => {
return (
<SafeAreaView>
<View
style={[mixins.margin(16,16)]}>
<ScrollView >
<View style={[mixins.margin(16,16), layout.display.flex, layout.justify.between, { backgroundColor:"orange", flexDirection: 'row', flexWrap: 'wrap' }]}>
{UKK_SEKUNDER.map((item, key) => (
<TouchableOpacity key={key} style={{ backgroundColor:"yellow", }}>
<View
style={[layout.margin.vertical(10)]}
>
<SmallMateriCard {...item} />
</View>
</TouchableOpacity>
))}
</View>
</ScrollView>
</View>
</SafeAreaView>
);
};
export default UKKSekunderScreen;
Thanks in advance.
EDIT
Gaurav's solution works but there's a new problem when I integrated it with my expandable component. The cards are overlaps when the component is collapsed.
EDIT 2
Solved by adding overflow: 'hidden'.
Hey check this please https://snack.expo.dev/HUhqzIpYv
Hope it helps :)
I believe your desired output would be a flex row with wrap enabled such as:
<View style={{flex: 1, justifyContent: 'flex-start', alignItems: 'center'}}>
<View style={{
justifyContent: 'flex-start',
alignItems: 'center',
flexDirection:'row',
flexWrap: 'wrap'
}}>
<Box style={{width: '50%'}} {...} />
<Box style={{width: '50%'}} {...} />
<Box style={{width: '50%'}} {...} />
<Box style={{width: '50%'}} {...} />
....
</View>
</View>
You could add some padding and margin to the box to add some space in-between them.
Edit: Here's an example with plain text, just to notice the layout:
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<View
style={{
justifyContent: 'flex-start',
alignItems: 'center',
flexDirection: 'row',
flexWrap: 'wrap',
}}>
<Text
style={{width: '40%', borderWidth: 2, padding: '10%', margin: '5%', textAlign: 'center'}}>
Text
</Text>
<Text
style={{width: '40%', borderWidth: 2, padding: '10%', margin: '5%', textAlign: 'center'}}>
Text
</Text>
<Text
style={{width: '40%', borderWidth: 2, padding: '10%', margin: '5%', textAlign: 'center'}}>
Text
</Text>
<Text
style={{width: '40%', borderWidth: 2, padding: '10%', margin: '5%', textAlign: 'center'}}>
Text
</Text>
<Text
style={{width: '40%', borderWidth: 2, padding: '10%', margin: '5%', textAlign: 'center'}}>
Text
</Text>
<Text
style={{width: '40%', borderWidth: 2, padding: '10%', margin: '5%', textAlign: 'center'}}>
Text
</Text>
<Text
style={{width: '40%', borderWidth: 2, padding: '10%', margin: '5%', textAlign: 'center'}}>
Text
</Text>
</View>
</View>

react-pdf/renderer - Cannot read properties of undefined (reading 'height')

EDIT: I've implemented what I needed using jsPDF instead of react-pdf/renderer so guess below doesn't matter anymore! Will leave up in case an answer helps someone in future.
I've tried troubleshooting everything I can think of with this one and need some help!
I'm trying to render a dynamic PDF using react-pdf/renderer but I keep getting the error message "Cannot read properties of undefined (reading: 'height') in console and the PDF does not display on web page.
So initially I had used <p> elements and from searching this is a no go so I switched all of those out for the <Text> but error persists. I was also attempting to style with tailwind before but I've also been through and removed all of that to use the styling from the docs.
I'm now at a loss, can't see anything else I shouldn't be doing. I've tried commenting out the mapping and moment functions as well just in case and that made no difference.
Code is below, first snippet is where I'm trying to render and then the second snippet is the full component. It wasn't originally in the "dashboard" which is why the invoice is an empty array, just moved it here as part of my troubleshooting (also didn't help).
Any guidance will be appreciated!
import React from "react";
import { useSelector } from "react-redux";
import { EuiFlexGroup, EuiFlexItem } from "#elastic/eui";
import InvoicePage from "../../pdf/InvoicePage";
import { PDFViewer } from "#react-pdf/renderer";
function DashboardScreen() {
const auth = useSelector((state) => state.auth);
const user = auth.user;
const viewInvoice = [""];
return (
<div className='flex flex-col mx-auto'>
<EuiFlexGroup
direction='column'
justifyContent='center'
alignItems='center'
className='w-full'
>
<EuiFlexItem>
<h2 className='text-5xl mt-10'>{user.firstName}'s Dashboard</h2>
</EuiFlexItem>
<EuiFlexItem className='mt-20 text-lg'>
Dashboard Coming Soon!
</EuiFlexItem>
</EuiFlexGroup>
<PDFViewer>
<InvoicePage user={user} invoice={viewInvoice} />
</PDFViewer>
</div>
);
}
export default DashboardScreen;
import { Page, Document, View, Text, StyleSheet } from "#react-pdf/renderer";
import React from "react";
import moment from "moment";
function InvoicePage({ invoice, user }) {
const styles = StyleSheet.create({
page: {
backgroundColor: "white",
},
});
return (
<Document>
<Page size='A4' style={styles.page}>
<View style={{ display: "flex" }}>
<View
style={{
display: "flex",
flexDirection: "column",
width: "50%",
border: "solid 1px gray",
padding: 8,
}}
>
<Text>Invoice To:</Text>
<Text>{invoice.clientName}</Text>
<Text>{invoice.clientAddrOne}</Text>
<Text>{invoice.clientCity}</Text>
<Text>{invoice.clientPostcode}</Text>
</View>
<View
style={{
display: "flex",
flexDirection: "column",
width: "50%",
marginLeft: 80,
border: "solid 1px gray",
padding: 8,
}}
>
<Text>Invoice From:</Text>
<Text>
{user.firstName} {user.secondName}
</Text>
<Text>{user.addrOne || ""}</Text>
<Text>{user.city || ""}</Text>
<Text>{user.postcode || ""}</Text>
</View>
</View>
<View
style={{
display: "flex",
flexDirection: "column",
marginTop: 32,
border: "1px solid gray",
padding: 8,
}}
>
<View style={{ display: "flex", width: "100%" }}>
<Text style={{ width: "35%", textDecoration: "underline" }}>
Invoice Number
</Text>
<Text style={{ width: "35%", textDecoration: "underline" }}>
Date Sent
</Text>
<Text style={{ width: "35%", textDecoration: "underline" }}>
Date Due
</Text>
</View>
<View style={{ display: "flex", width: "100%", marginTop: 8 }}>
<Text style={{ width: "35%", paddingLeft: 48 }}>
{invoice.invoiceNumber}
</Text>
<Text style={{ width: "35%" }}>
{moment(invoice.sentDate).format("Do MMMM YYYY")}
</Text>
<Text style={{ width: "35%" }}>
{moment(invoice.dueDate).format("Do MMMM YYYY")}
</Text>
</View>
</View>
<View
style={{
display: "flex",
flexDirection: "column",
border: "1px solid gray",
marginTop: 8,
marginBottom: 8,
padding: 8,
}}
>
<View style={{ display: "flex", width: "100%", marginBottom: 8 }}>
<Text style={{ width: "50%", textDecoration: "underline" }}>
Task Description
</Text>
<Text style={{ width: "17%", textDecoration: "underline" }}>
Hours
</Text>
<Text style={{ width: "17%", textDecoration: "underline" }}>
Rate
</Text>
<Text style={{ width: "17%", textDecoration: "underline" }}>
Price
</Text>
</View>
{invoice.tasks.map((task) => {
const time = task.hours + task.minutes / 60;
const price = time * invoice.hourlyRate;
return (
<View style={{ display: "flex", width: "100%" }}>
<Text style={{ width: "50%" }}>{task.taskDescription}</Text>
<Text style={{ width: "17%" }}>{time.toFixed(2)}</Text>
<Text style={{ width: "17%" }}>{invoice.hourlyRate}</Text>
<Text style={{ width: "17%" }}>£{price.toFixed(2)}</Text>
</View>
);
})}
</View>
<View style={{ display: "flex", justifyContent: "space-between" }}>
<View
style={{
display: "flex",
flexDirection: "column",
border: "1px solid gray",
padding: 8,
width: "40%",
}}
>
<View style={{ display: "flex" }}>
<View style={{ textDecoration: "underline", marginBottom: 8 }}>
<Text>Payment Details</Text>
</View>
</View>
<View>
<View>
<Text>Payment Method:</Text>
</View>
<View>
<Text>{invoice.paymentMethod}</Text>
</View>
</View>
<View
style={{ display: "flex", flexDirection: "column", marginTop: 8 }}
>
<View>
<Text>Account Number:</Text>
</View>
<View>
<Text>{invoice.accountNumber}</Text>
</View>
</View>
<View
style={{ display: "flex", flexDirection: "column", marginTop: 8 }}
>
<View>
<Text>Sort Code:</Text>
</View>
<View>
<Text>{invoice.sortCode}</Text>
</View>
</View>
</View>
<View
style={{ display: "flex", flexDirection: "column", width: "50%" }}
>
<View
style={{ display: "flex", border: "1px solid gray", padding: 8 }}
>
<View style={{ width: "50%" }}>
<Text>Total:</Text>
</View>
<View style={{ width: "50%" }}>
<Text>£0.00</Text>
</View>
</View>
<View
style={{ display: "flex", flexDirection: "column", marginTop: 8 }}
>
Thank you for your business!
</View>
</View>
</View>
</Page>
</Document>
);
}
export default InvoicePage;
Just a simple solution, I think work in your case. You have to mention height of your <PDFViewer> element like
<PDFViewer style={{ height: "50vh", width: "100%"}}>
<InvoicePage user={user} invoice={viewInvoice} />
</PDFViewer>
OR
<PDFViewer style={styles.PDFContainer}>
<InvoicePage user={user} invoice={viewInvoice} />
</PDFViewer>
const styles = StyleSheet.create({
PDFContainer: {
width: "100%",
height: "50vh", //As per your page layout
}
}
I know this question is old, but anyway...
It's looks like you need to add <Text> tag to Thank you for your business! at the end of file.

Flexbox - React Native

i am new to react native and i am trying to make a chat app layout.
As you can see in screenshot that i have attached, i want text box to take as much space as the text in it. For example, if i send 'Hi', it should only be stretched as much space 'Hi' needs.
If i send a long text, then it should stretch and take as much space as that text is. Like it happens in almost all texting apps.
The text box code is:
<TouchableOpacity>
<View style={styles.containerSent}>
<View style={{flex: 3}}>
<Text style={styles.message}>{item.message}</Text>
</View>
<View style={{flex: 1}}>
<Image
source={require('../assets/images/check.png')}
style={styles.image}
/>
<Text style={{textAlign: 'right', color: 'white'}}>
{msToTime(item.timestamp)}
</Text>
</View>
</View>
</TouchableOpacity>
Stylesheet
containerSent: {
flex: 1,
maxWidth: '70%',
// minWidth: '30%',
marginTop: 20,
paddingTop: 20,
paddingHorizontal: 10,
paddingBottom: 10,
borderWidth: 1,
backgroundColor: '#6F2232',
borderRadius: 20,
alignSelf: 'flex-end',
flexDirection: 'row',
justifyContent: 'space-between',
// justifyContent: 'flex-end',
},
message: {
color: 'white',
fontSize: 15,
fontWeight: 'bold',
textAlign: 'left',
alignSelf: 'stretch',
},
image: {
width: 15,
height: 15,
marginLeft: 20,
marginBottom: 5,
alignSelf: 'flex-end',
},
How I have implemented this is that I removed flex: 3 and flex: 1 from both the elements so that they don't expand to take the max space, and I added flexShrink: 1 to the text, so that it always shrinks keeping the right element intact.
Snack link
Set View style to flex: 0 so it‘s just taken as Maus h space as necessary.
<TouchableOpacity>
<View style={styles.containerSent}>
<View style={{ flex: 0 }}>
<Text style={styles.message}>{'q.a'}</Text>
</View>
<View style={{ flex: 0, paddingLeft: 10 }}>
<Text style={styles.message}>{'eeeee.message'}</Text>
</View>
</View>
</TouchableOpacity>
Take a look at my sample

react native view overflow

I'm trying to imitate the image.
I'm having a problem with the button with the like in the middle I can not imitate it.
Since I read it seems that native react on android has a problem with overflow.
I thought you could use a:
marginTop: -25
but it does not seem to solve the problem.
Some advice?
Link expo: https://snack.expo.io/Hk1yUyzB7
Code:
import React, { Component } from 'react';
import { View, StyleSheet, Image, Text } from 'react-native';
//import ViewOverflow from 'react-native-view-overflow';
export default class App extends Component {
render() {
var account = (
<View>
<View
style={{
paddingTop: 20,
paddingLeft: 20,
flexDirection: 'row',
}}>
<Image
style={{ width: 50, height: 50, borderRadius: 25 }}
source={{
uri:
'http://www1.pictures.zimbio.com/bg/Number+Four+World+Premiere+h5-FoI0M8-gl.jpg',
}}
/>
<View
style={{
paddingLeft: 20,
}}>
<Text>Yulia James</Text>
<Text
style={{
color: '#ccc',
}}>
6 hrs · IIT London
</Text>
</View>
</View>
<Text
style={{
paddingTop: 20,
paddingLeft: 20,
paddingBottom: 20,
}}>
Making everyday worth it :)
</Text>
<View
style={{
paddingBottom: 20,
}}>
<Image
style={{
width: '100%',
height: 200,
}}
source={{
uri:
'http://www.wordzz.com/wp-content/uploads/2016/11/Night-Ratri.jpg',
}}
/>
</View>
</View>
);
var com = (
<View
style={{
backgroundColor: 'rgba(230,230,230,0.8)',
//height: 40,
alignItems: 'center',
//justifyContent: 'center',
padding: 5,
flex: 1,
}}>
<Text
style={{
color: '#ccc',
fontSize: 18,
}}>
Comment
</Text>
</View>
);
return (
<View
style={{
flex: 1,
backgroundColor: '#e7eff0',
}}>
<View
style={{
backgroundColor: 'rgba(255,255,255,0.8)',
marginTop: 50,
borderTopWidth: 1,
borderBottomWidth: 1,
borderColor: '#e7e7e7',
}}>
{account}
<View
style={{
backgroundColor: '#fff',
borderTopWidth: 1,
borderColor: '#ccc',
//alignItems: 'center',
//justifyContent: 'center',
}}>
<View style={styles.container2}>
{com}
<View
style={{
//backgroundColor: '#000',
borderRadius: 40,
height: 80,
width: 80,
alignItems: 'center',
justifyContent: 'center',
borderColor: '#ccc',
borderWidth: 1,
}}>
<Image
style={{
//resizeMode: 'cover',
height: 40,
width: 40,
}}
source={{
uri: 'http://i.imgur.com/k5jMsaH.gif',
}}
/>
</View>
{com}
</View>
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container2: {
flexDirection: 'row',
},
});

Create full width and height box inside ScrollView with React Native

How can I, in React Native, make a simple ScrollView with black background in which I have a white box with 20px margin around the box?
I have tried
<ScrollView style={{ backgroundColor: '#000', flex: 1 }}>
<View style={{ flex: 1, margin: 20, backgroundColor: '#fff' }}
<Text>Text</Text>
</View>
</ScrollView>
but it doesn't fill up the full width and height of the screen.
You should use padding in ScrollView like this:
<ScrollView style={{ backgroundColor: '#000', flex: 1, padding: 20}}>
<View style={{ flex: 1, backgroundColor: '#fff' }}>
<Text>Text</Text>
</View>
</ScrollView>

Categories

Resources