Make child container occupy height of parent container [React Native] - react-native

I made a <View> object in react native containing, in a row, multiple <View> objects that contain text objects.
When the text is more than 1 line, the text containers do not expand to fill the parent component and it looks funny.
Screenshot:
This is the style code:
bigContainer: {
flex: 1,
justifyContent: 'center',
// flexDirection: 'row'
},
textContainer: {
flex: 1,
paddingLeft: 0,
paddingRight: 0,
borderRightWidth: 1,
borderRadius: 0,
borderColor: 'rbga(0, 0, 0, 0.1)',
alignItems: 'center',
justifyContent: 'center',
paddingTop: 7,
paddingBottom: 7,
overflow: 'hidden'
},
text: {
fontSize: 18,
textAlign: 'center'
},
Please help, I do not understand why this happens since I have flex: 1 and my research has not helped me. Thanks !!
UPDATE: SOLVED: I forgot that <TouchableOpacity>, the container that encloses the text container, also behaves like a flexbox

In React Native flex works a bit differently, as it only accepts a single number. This is because of the Yoga layout engine facebook uses
flex: 1 does not mean "grow as much as you need to". When you assign a group of child components that property, what you're essentially saying is that each element with the flex: 1 property should take up as much space as each other element. Think of flex: 1 as assigning a ratio. If you have 1 element with no siblings, it will attempt to fill all available space. If you have 4 elements and they are all siblings, and they are all set to flex: 1 then each will take 1/4 (25%) of the available space.
This can be manipulated as well, say you have 4 elements and 3 of them are set to flex: 1. You can set the 4th to flex: 2. That 4th element will now use twice as much space as the other components (40% of available space as opposed to 20%). Flex can also be set to a negative number, which means it will shrink to it's min height and width when needed.
This behavior is pretty much identical to how the flex-grow property works in CSS. If you want to manipulate the initial size of a flex container without respect to it's siblings, you should use the flex-basis (flexBasis in react) property. flexBasis: content will resize the container based on it's content. flexBasis also accepts a number, if you would like to manually set the initial width of your containers.

Related

Use space-around without setting height value

I want to put 3 texts on the screen one on the top, one on the middle an one on the bottom. For this I thought about using the space-around property. This is my code
<Screen style={styles.container} backgroundColor={color.transparent}>
<View style={styles.playerContainer}>
<View><Text>text 1</Text></View>
<View><Text>text 2</Text></View>
<View><Text>text 3</Text></View>
</View>
</Screen>
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'blue'
},
playerContainer:{
flexDirection: 'column',
justifyContent: 'space-around',
alignItems: 'center',
backgroundColor: 'red',
}
});
This is not working as expected. It looks better is I set a height for playerContainer, but I am enable to calculate the right hight because of the navigation bar etc.. I just need to add three text in the container. I must calculate the hight of playerContainer or I am doing something wrong?
If you want the first entry to be at the start of the container, the second to be at the center, and the last to be at the end, you need justifyContent: 'space-between'. I found this article helpful when learning about flex in React Native https://blog.reactnativecoach.com/understanding-flex-in-react-native-b34dfb4b16d1

React Native minHeight acting like paddingBottom, how is this happening?

I have one container that wraps some children. The number of children is dynamic, and when there are none, the parent container is not visible. To address this, I added the minHeight value, and perfect, it worked as expected. However, when there are children, this minHeight is somehow behaving as padding-bottom, for sure.
I know this sounds crazy, and it's been driving me crazy, but I'm sure of it. I know this to be the case because I've reviewed all the styling over and over and when I remove the minHeight value when there are two rows or more of children, this effect goes away! However, now I'm back to square one which is the parent is not visible without this minHeight when there are no children. So I have no idea how to fix this. I've replicated the situation on this Snack demo, and strangely, it behaves just fine there. So I have no idea how the heck this is happening, does anyone have any idea what setting might cause minHeight to behave like a padding-bottom?
With minHeight:
Without minHeight (but now I can't see black background when no children are present):
you need to know the height for children to order put the correct height for the parent
you can handle height for children in const like this
const HEIGHT_ELEMETE=20
then put this var in your style
parent: {
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'flex-start',
backgroundColor: 'black',
borderRadius: 5,
padding: 2,
minHeight: HEIGHT_ELEMETE,
},
element: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: 'grey',
padding: 2,
margin: 2,
borderRadius: 5,
height:HEIGHT_ELEMETE
},
expo

Display as a row unless it would overflow the container in which case display as a column?

Pretty straightforward question. I have a react-native app. I have a container with three elements in (a string, a graph and a number). I want those elements to display as a row, unless it would spill over the edge of the screen in which case I want it to display as a column. The reason for this is that the row looks better, but due to internationalisation, the string in question could potentially get quite long, in which case the rest of the contents of the container are pushed off the screen which obviously looks bad and isn't user friendly. If this is the case I'd prefer it to format as a column as then the user could simply scroll down and view the full information.
This is the current styling:
container: {
flex: 1,
flexShrink: 1,
flexDirection: "row",
alignContent: "space-between",
alignItems: "center",
backgroundColor: "white",
margin: "1rem",
marginTop: "0.2rem",
marginBottom: "0.2rem",
justifyContent: "space-evenly"
},
Simply removing flexDirection: row causes it to display as a column which I'd prefer not to be the default case.

width: '100%' vs Dimension.get('window').width in react native

I'm new to react native and css styling as a whole so sorry if the question is very basic. I want a view to take 100% of the available screen width and when i use the code below my view seems to go outside the screen boundry, though when I use Dimension.get('window').width it work just fine. can someone explain how they differ from each other. any help would be really appreciated. thanks
return(
<TouchableOpacity style = {styles.food_wrapper}
onPress = {()=> this.userAction()}
>
<Text style = {styles.foodname}>
{this.name}
</Text>
<Text style = {styles.foodprice}>
Rs: {this.price}
</Text>
</TouchableOpacity>
);
food_wrapper:{
flex: 1,
flexDirection :'row',
justifyContent:'space-between',
alignItems:'flex-start',
width: '100%',//Dimensions.get('window').width,
minHeight: 50,
marginVertical: '1%',
padding: '2%',
backgroundColor: 'rgb(155,200,200)'
},
You need to understand what is the basic difference from 100% and the width you get using dimension.get('window')
100% means you want to get the container 100% width which mean if your parent container is 50px then 100% will return 50px.
the width from dimension give you a static width of your device width
so be careful to choose what to use to your component
if you want to follow the parent container then it is easier to use 100% then width from dimension but for responsive reasons without any parent container or it is the parent itself then width from dimension will work better
You need to add a wrapper view with flexDirection: 'row', then style the child view (or Touchable or whatever) with flex: 1
<View style={{ flexDirection: 'row' }}>
<View style={{ flex: 1, height: 100, backgroundColor: 'grey' }} />
</View>
Or you could use alignSelf: 'stretch' inside a few with flexDirection: 'column' (which is the default for all views)
Hang in there. Learning flexbox takes some practice. Your first thought when you get stuck should be "do I need to add a wrapper view?"

React Native chat bubble flexbox similar to whatsapp

I'm trying to create a chat view in React Native similar to the Whatsapp UI.
What I can't wrap my head around is - how to do the time. Here is how it looks in Whatsapp:
Notice that the time is not on a completely new line by itself, but half a line.
At the same time in the last comment you can see that if the text is long enough, the time is being pushed to a new line.
I've tried several things:
Make the bubble relative and then use absolute positioning on the time element. Unfortunately if the text is long enough my time overlaps the text.
Make the bubble flexDirection: "row", and then have the text in 1 view and the time in another view. But I can't figure out how to force a wrap when the text is "long enough".
Any ideas how to achieve this?
I managed to kind of get what I want. It's not 100% the same as whatsapp, but good enough.
I had the following code:
<View style={{
margin: 10, marginTop: 10, marginBottom: 0,
padding: 10, borderRadius: 5, paddingBottom: 10,
backgroundColor: cropType ? '#93D14C' : '#F1F0F5'
}}>
{this.renderContent(comment)}
<Text
style={[styles.muted,
{
color: constants.FJMUTEDLIGHT,
backgroundColor: 'transparent',
alignSelf: 'flex-end',
fontSize: 12,
marginBottom: -5,
marginTop: 2
}]}>{moment.utc(comment.created).local().format('HH:mm')}</Text>
</View>
The renderContentHere() function can render Text, but it also can render a complex View containing text. Initially I wanted to figure out how many lines a text has and to figure the width of the lines. This doesn't seem to be possible with React Native since the onLayout property on a Text node can only tell you the width and height of the element, but not if the Text is 2 lines or 3 lines.
So I decided to just measure the View that contains the comment and figure out if it has one or more lines. If it has one line I'm assuming that I can place the time a little higher than normally.
This is what I ended up doing:
<View style={{
margin: 10, marginTop: 10, marginBottom: 0,
padding: 10, borderRadius: 5, paddingBottom: 10,
backgroundColor: cropType ? '#93D14C' : '#F1F0F5'
}}>
<View style={this.state.oneLine ? {
// Since we don't know how long the one line is, just in case add 25px padding on the right
// this way even if we are dealing with a long line of text it won't end up over the time
paddingRight: 25
} : {}}
onLayout={(e) => {
let {height} = e.nativeEvent.layout
// if height is less than 30px, then we are dealing with a single line of content
if (height < 30) {
this.setState({'oneLine': true})
}
}}>
{this.renderContent(comment)}
</View>
<Text
style={[styles.muted,
{
color: constants.FJMUTEDLIGHT,
backgroundColor: 'transparent',
alignSelf: 'flex-end',
fontSize: 12,
marginBottom: -5,
// If one line, move the time up - there is enough space
marginTop: this.state.oneLine ? -10 : 2
}]}>{moment.utc(comment.created).local().format('HH:mm')}</Text>
</View>
If we have a single line it still possible that the text will end up behind the time, so that's why I'm applying a right padding on the Text of 25 px. This breaks long lines and we end up with a view like this: