React Native Add Spacing Between Components - javascript

I need help fixing the overlap of views in my react native app (Need spacing between them).
After pressing the plus sign twice in top right corner, the two Views end up overlapping without any space between them (Which are called HoldWorkout Components)
Image of overlap
My App.js contains:
let PRs = PRArray.map((val, key) => {
return (
<HoldWorkout
key={key}
keyval={key}
val={val}
exName={setName}
setsHold={setSets}
/>
);
});
PRs is contained in the following Scroll View on Return:
<View style={styles.container}>
<View style={styles.whiteColor}>
<TouchableOpacity
activeOpacity={0.5}
onPress={addPR.bind(this)}
style={styles.TouchableOpacity}
>
<Icon name="ios-add" color="purple" size={45} />
</TouchableOpacity>
<View style={styles.header}>
<Text style={styles.headerTitle}>Personal Records</Text>
</View>
</View>
<ScrollView style={styles.scrollViewStyle}>
<View style={styles.color}>{PRs}</View>
</ScrollView>
</View>
The Styles in App.js is:
const styles = StyleSheet.create({
whiteColor: {
backgroundColor: "white",
borderBottomColor: "#F0EFF5",
borderBottomWidth: 2,
height: 80
},
container: {
flex: 1,
borderBottomColor: "#F0EFF5",
borderBottomWidth: 2
},
color: {
marginTop: 20,
backgroundColor: "#F0EFF5"
},
});
In HoldWorkout.js on return I have
<View key={props.keyval} style={styles.boxWorkouts}>
<TextInput
style={styles.input2}
placeholder="Excercise Name"
placeholderTextColor="#a9a9a9"
onChangeText={props.exName}
/>
<ExSets weight={setWeights} rep={setRep} date={setDates} />
{sets}
<View style={styles.addSet}>
<Button title="Add Set" color="purple" onPress={addSets}></Button>
</View>
</View>
The Style for the View is style.boxWorkouts which is in HoldWorkout.js and looks like
const styles = StyleSheet.create({
boxWorkouts: {
borderColor: "#BFBFBF",
borderWidth: 1,
backgroundColor: "white",
height: 90
}
});
I tried adding marginBottom: 100 to styles.boxWorkouts but that is fixed amount and if I click "Add Set" button on one of the HoldWorkout Components then it will add another row which will increase the height of the component and end up overlapping the component underneath it.
Image of after clicking Add Set on first Hold Workout Component with marginBottom set to 100
Please help on telling me how to fix the spacing for this as I have been trying to figure it out for a while because I am not sure how to get the components pushed down when I click "Add Set" button on the components above. This will ensure it wont overlap no matter how many times "Add Set" is pressed on the HoldWorkouts Components Above.

You need to add empty row or empty div with spacing as below.
let PRs = PRArray.map((val, key) => {
return (
<div>
<HoldWorkout
key={key}
keyval={key}
val={val}
exName={setName}
setsHold={setSets}
/>
<div> <br/> </div>
</div>
);
});

Related

How to fix Error not warning: ERROR VirtualizedLists should never be nested inside plain ScrollViews. Even when ScrollViews isn't used

I am trying to build a react-native app, and I want to build a layout where I have components in a vertical manner and a transaction history, I am stuggling with the component to view transaction history which I am populating from a dummy data, I am faced with an error "VirtualizedLists should never be nested inside...". Even when I am not using ScrollViews. I have tried a couple of stackoverflow answers but it is still the Error (Not warning). Here is my Code:
`
import React from 'react';
import {View, Text, FlatList, TouchableOpacity, Image} from 'react-native';
import {colors, SIZES, fonts, icons} from '../global';
const TransactionHistory = ({customContainerStyle, history}) => {
const renderItem = ({item}) => (
<TouchableOpacity
style={{
flexDirection: 'row',
alignItems: 'center',
paddingVertical: SIZES.base,
}}
onPress={() => console.log(item)}>
<Image
source={icons.transaction}
style={{
width: 30,
height: 30,
tintColor: colors.primary,
}}
/>
<View style={{flex: 1, marginLeft: SIZES.radius}}>
<Text style={{...fonts.android.h3}}>{item.description}</Text>
<Text style={{color: colors.gray, ...fonts.android.body4}}>
{item.date}
</Text>
</View>
</TouchableOpacity>
);
return (
<View
style={{
marginTop: SIZES.padding,
marginHorizontal: SIZES.padding,
padding: 20,
borderRadius: SIZES.radius,
backgroundColor: colors.white,
...customContainerStyle,
}}>
<Text style={{...fonts.android.h2}}>Transaction History</Text> //Transaction History Heading
<FlatList
contentContainerStyle={{marginTop: SIZES.radius}}
scrollEnabled={false}
data={history}
keyExtractor={item => `${item.id}`}
renderItem={renderItem}
showsVerticalScrollIndicator={false}
ItemSeparatorComponent={() => {
return (
<View
style={{
width: '100%',
height: 1,
backgroundColor: colors.lightGray,
}}></View>
);
}}
/>
</View>
);
};
export default TransactionHistory;
`
What I tried?
One of the answers was to change the ScrollView tag to View, but I already used the view tag and not ScrollView.
Change ScrollEnabled to be False. This was false initially.
According to this solution (React-Native another VirtualizedList-backed container). I used I created the Flatlist outside of the View and used ListFooterComponent to call it. Still the same Error.
Expected Outcome:
I am Meant to have the populated data after the Transaction History Heading. Please let me know, if there is any solution to this, or another way to fufill the task. Thanks
I had a similar issue once where I was using a ScrollView in a shared Container parent component. Maybe worth checking again to see if TransactionHistory isn't nested under and ScrollView parent somewhere on the Screen.
Once I figured it was nested under a ScrollView, I essentially removed the Container and added the header and footer component around my SectionList using the ListHeaderComponent and ListFooterComponent props on the SectionList achieving the same functionality of having a ScrollView parent.
Example:
<SectionList
renderSectionHeader={renderSectionHeader}
sections={data}
ListHeaderComponent={Header}
renderItem={renderItem}
contentContainerStyle={{ paddingBottom: bottom }}
/>
More info here

React Native: Why my text breaks like this and why is it not respecting the container margin?

I want to display multiple elements next to each other in React Native (with a flex wrap if there are too many elements or if the elements are too long). Each element consists of an icon and a text. If the text is too long, the text should break into the next line.
I tried different things with flexGrow and flexShrink but nothing had the desired effect. Here is my code (expo snack):
export default function App() {
function iconWithText(text) {
return (
<View style={styles.iconWithTextWrapper}>
<View style={{paddingRight: 10, backgroundColor: 'grey'}}>
<Text>Icon</Text>
</View>
<View style={{backgroundColor: 'yellow'}}>
<Text>{text}</Text>
</View>
</View>
)
}
return (
<View style={styles.container}>
{iconWithText('short text')}
{iconWithText('short text')}
{iconWithText('this is a long, long, long text that does break very ugly')}
</View>
);
}
const styles = StyleSheet.create({
container: {
marginTop: 50,
marginHorizontal: 50,
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'flex-start',
},
iconWithTextWrapper: {
flexDirection: 'row',
margin: 10,
}
});
Here is the corresponding result - as you can see the margin of the whole container is not respected and the text does not break very well:
Why is the right margin of the container not respected, why does the text break like this and how can I fix this?
Try adding a flex:1 to your text style.
edit:
I played around in your snack and came up with this:
https://snack.expo.io/#moistbobo/iconwithtext
Please see if this fits your use case.

Is there a way to make a sized and functional FlatList inside a Modal?

Good evening!
I have been trying to create a modal with a scrollable FlatList inside, but such FlatList should have its height size reduced. The modal is going to search a wide list of airports, so basically a lot data might be shown, hence why FlatList is the best tool for this occasion. Basically, the modal screen would look like this picture below:
However, I can't make the scroll inside FlatList work no matter what. Here is the code, with the FlatList that is somewhat functional, but it has a warning:
const styles = StyleSheet.create({
modalContainer: {
backgroundColor: 'rgba(50,50,50,0.6)',
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
modalActivityContainer: {
backgroundColor: colors.colorWhite,
borderColor: colors.colorLightBlack,
borderWidth: 2,
borderRadius: 20,
padding: props.padding ? Number(props.padding) : 10,
maxWidth: '85%',
},
modalHeader: {
flexDirection: 'row',
justifyContent: 'center',
},
headerAirportModal: {
backgroundColor: colors.colorGrey,
borderTopRightRadius: 20,
borderTopLeftRadius: 20,
paddingHorizontal: 5,
paddingVertical: 10,
width: '100%',
justifyContent: 'center',
},
searchAirportBarContainer: {
backgroundColor: colors.colorWhite,
height: 40,
},
...
<Modal
onRequestClose={() => props.onRequestClose()}
animationType="fade"
transparent
visible={props.showModal}>
<TouchableWithoutFeedback
onPress={() => {
props.onRequestClose();
}}>
<View style={styles.modalContainer}>
<TouchableWithoutFeedback>
<View style={styles.modalActivityContainer}>
<View style={styles.modalHeader}>
<View style={styles.headerAirportModal}>
<Item style={styles.searchAirportBarContainer} rounded>
<Icon
style={styles.iconSearchAirport}
type="FontAwesome5"
name="search"
/>
<Input
style={styles.searchAirportBarText}
placeholderTextColor={colors.colorLightBlack}
placeholder="Search by Airport, Country or City"
/>
</Item>
</View>
</View>
<View>
<View style={styles.modalHeader}>
<Grid style={styles.headerAirportModalBackground}>
<Text style={styles.headerAirportModalText}>Latest Searches</Text>
<TouchableOpacity style={styles.clearButtonLatestContainer}>
<View>
<Text style={styles.clearButtonAirport}>Clear</Text>
</View>
</TouchableOpacity>
</Grid>
</View>
</View>
<View style={{maxHeight: 250}}>
<ScrollView>
<View onStartShouldSetResponder={() => true}>
<FlatList
data={airportElements}
renderItem={renderAirportItem}
keyExtractor={(item) => item.id}
/>
</View>
</ScrollView>
</View>
<Button
backgroundColor={colors.colorRed}
alignSelf="stretch"
buttonStyle={styles.finishButton}
onPress={() => {
setModalSelectAirport(false);
}}>
Cancel
</Button>
</View>
</TouchableWithoutFeedback>
</View>
</TouchableWithoutFeedback>
</Modal>
If I use the FlatList inside the ScrollView like shown above, the code works as intended. However, I got this warning:
VirtualizedLists should never be nested inside plain ScrollViews
with the same orientation - use another VirtualizedList-backed
container instead.
Because of that, I can't use FlatList properly. Also, I have managed to make it work with .map, but it was advised to not use it as I am going to load a list with a lot of elements and that might cause lag.
I have managed to implement FlatList in another way like this:
<View
style={styles.airportLatestSearchListContainer}>
<FlatList
contentContainerStyle={styles.airportLatestSearchlist}
data={airportElements}
renderItem={renderAirportItem}
keyExtractor={(item) => item.id}
/>
</View>
This, however, prevents the user to scroll. The list remains static and the user can't scroll at all.
I have tried using {flex: 1, flexGrow: 1} in the parent View and FlatList itself, both don't work at all, even inside the FlatList container or the style.
Can someone please help me with this one? I really appreciate the time and effort! Thanks!

How can I change the colour of a button in react native without reseting state?

I'm currently building a screen in react native that has a bunch of horizontal flatLists stacked vertically. Think uber eats, Spotify and Netflix.
The horizontal flatLists contain cards.
I have added like and share buttons to these cards. I want my users to be able to save or like the item in the card while scrolling. The way you can on instagram.
I click one the buttons to send a request to the backend which works.
The problem I am facing is that I want the buttons to change colour when I press them.
What I would normally do is place a new variable in state, that gets changed when the request to the backend is done.
The problem with this approach is that, it causes state to reload. This cause my component screen to reload. This is not an ideal user experience. I don't want the whole screen to flash when someone presses a button.
I also don't want my users to lose their place on the screen.
Is there a better approach that allows me to:
1) press the button
2) update the backend
3) Have my button change colour.
constructor(props) {
super(props)
this.state = {
card: [],
saved: false,
shared: false
}
}
<FlatList
data={card}
keyExtractor={(index, item) => Math.random().toString()}
horizontal
renderItem={({ item }) => {
return (
<View>
<TouchableOpacity
onPress={() => this.description(item)}
>
<Card image={{uri: item.img}} containerStyle={{width: width * 0.8, height: height * 0.4}} >
<View style={{height: 60, justifyContent: 'center'}}>
<Text style={[textStyle, {fontSize: 16}]}>{item.name}</Text>
</View>
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent:'space-between', width: width * 0.7 }}>
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
</View>
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
<View>
<Icon
name='bookmark'
type='Feather'
onPress={() => this.save(item._id)}
color={userHasPressedSave.includes(item._id) ? '#FF0000' : null}
/>
</View>
<View>
<Icon
name='ios-heart'
type='ionicon'
onPress={() => this.shared(item._id)}
/>
</View>
</View>
</View>
</Card>
</TouchableOpacity>
</View>
)
}
}
/>
This should be obvious ... If you don't want to modify 'global'/parent state then use 'local'/child state - just convert buttons into components.
Pass handlers to be able to call backend requests.
Use their local state to change color, content (like/unlike label), enable/disable, counter... whatever you need ... just 'think in react' ... tree of components.
You can also store changes in parent (within handlers) as class/object properties. Updating them (as opposed to updating the state) won't force rerendering but you will be able to use them when a rerender occurs.

React Native FlatList with clickable items

I'm building a custom line style for a react-native FlatList.
I want the user to navigate to item details when clicking on the line text, or navigate to another page (drill down next level) when clicked on the right caret, something like:
Here is my current list components code:
class MyList extends Component {
handleShowDetails = index => {
...
};
handleDrillDown = index => {
...
}
render = () => {
let data = // Whatever data here
return (
<View style={styles.container}>
<FlatList
data={data}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<MyListItem
onTextPress={this.handleShowDetails}
onCaretPress={this.handleDrillDown}
item={item}
/>
)}
/>
</View>
);
};
}
export default MyList;
const styles = StyleSheet.create({
container: {
flex: 1
},
item: {
padding: 10,
fontSize: 18,
height: 44,
backgroundColor: colors.white,
borderStyle: "solid",
marginBottom: 1
}
});
And my list item component:
class MyListItem extends Component {
handleTextPress = () => {
if (this.props.onTextPress) this.props.onTextPress(this.props.item.id);
};
handleIconPress =() => {
if (this.props.onCaretPress) this.props.onCaretPress(this.props.item.id)
}
render = () => {
return (
<View style={styles.container}>
<View style={styles.textContainer}>
<Text onPress={this.handleTextPress}>{this.props.item.title}</Text>
</View>
<View style={styles.iconContainer}>
<Button onPress={this.handleIconPress}>
<Icon name="ios-arrow-forward"/>
</Button>
</View>
</View>
);
};
}
export default MyListItem;
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
backgroundColor: colors.white,
marginBottom: 1,
height: 30
},
textContainer: {
backgroundColor: colors.light,
paddingLeft: 5,
fontSize: 26
},
iconContainer: {
alignSelf: "flex-end",
backgroundColor: colors.primary,
paddingRight: 5,
fontSize: 26
}
});
Problems I'm facing:
a. Clicking on text is not working properly. Sometimes it navigates but most of time I cannot navigate, specially if I click on the empty space between the text and the caret.
b. I simply cannot style the fontSize of the text.
c. I'm not being able to space then accordingly.
d. I need to vertical center both itens on row.
Here is what I'm getting for now:
For the clicking issue, you could set an TouchableHighlight or a TouchableOpacity for the View.
For spacing and alignment issues, maybe you could set the text to flex: 9 and the icon to flex: 1 with FlexBox. Here are the docs for that https://facebook.github.io/react-native/docs/flexbox.html.
a. Try to make the text full the cell. I can see your text just in 50% of the cell. style <Text> with height: 44
b. fontsize has to be placed in the <Text> component. You are placing it in <View> component
c. "I'm not being able to space then accordingly". I can't get your point clearly.
d. Try justifyContent: 'center' in iconContainer
For part a I would suggest an improvement over Anthu's answer:
I you want the entire textContainer to be clickable I suggest using TouchableWithoutFeedback (or another Touchable which suits your needs) and wrap this around the textContainer View

Categories