What is the exact purpose of setting rule flex: 1 to many React Native components?
Very often I can see this rules applied to different components. Sometimes this rules obviously redundant. Sometimes no obviously, but layout seems working well without it.
So, what exactly this rule suppose to do?
If the component is rendering fine without using flex: 1 it is obviously not needed. You might as well want to remove the unwanted style. What flex: 1 does is that it tells the component to occupy as much space as it can.
For example:
<View style={{ flex: 1, backgroundColor: '#cccccc' }}>
<Text>Hi</Text>
</View>
This will span the whole screen.
However, if you place another View at the same level in the DOM, both of the Views will occupy equal space i.e. the screen will be divided in two parts.
Like this:
<View style={{ flex: 1 }}>
<View style={{ flex: 1, backgroundColor: '#cccccc' }}>
<Text>View one</Text>
</View>
<View style={{ flex: 1, backgroundColor: '#eaeaea' }}>
<Text>View two</Text>
</View>
</View>
I agree that flexbox is a little bit confusing. But once you get the hang of it, you'll learn how to manipulate the views.
Edit: Always wrap child components with a parent component in order to avoid potential runtime errors.
For layout React Native uses flexbox because display: flex; is extremely well-suited for creating responsive layouts across various screen sizes and devices. All the attribute names and values are listed in the React Native docs.
In other words, instead of using display: block with various floats your layout should be created using flexbox rules.
Modus Create did a nice tutorial on Flexbox in React Native.
Specifically, that rule:
flex: 1
is telling the element to grow to fill the available space.
Related
Is it possible to implement ReactNative layout containing two components, where 2nd component overlaps 1st one and has the same width, possibly also same height (without hardcoding width/height of course)? It is easy to implement something like that in native Android, but I can't find example for ReactNative. I'd be surprised if it is not possible though.
You could try below
<View style={{ flex: 1 }} >
<View style={{ flex: 1 }}>
// 1st component
<View>
<View style={StyleSheet.absolueFill}>
// 2st component
<View>
<View>
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?"
Does anyone know how I can include the header of a flatlist in the columns?
For example, in the image below I would like "Design" to follow "New +" in the same row.
Example Screenshot
Here is my code in render:
<FlatList
data={goalItems}
extraData={this.props}
renderItem={this._renderGoal}
ListHeaderComponent={this._renderGoalHeader}
keyExtractor={item => item.goal_id}
showsVerticalScrollIndicator={false}
numColumns={2}
/>
and in _renderGoal:
_renderGoal = ({ item }) => (
<TouchableOpacity
onPress={() => this.openOptions(item)}
style={{ padding: 10 }}>
<Bubble>
<Text style={[styles.normalText]}>{item.name}</Text>
<View style={{ alignItems: 'center' }}>
<Text>{formatSeconds(item.total_time)}</Text>
</View>
</Bubble>
</TouchableOpacity>
);
and in _renderGoalHeader:
_renderGoalHeader = () => (
<TouchableOpacity
onPress={() => this.openAddGoal()}
style={{ padding: 10 }}>
<Bubble style={[styles.newGoal]}>
<Text style={[styles.touchableText]}>New +</Text>
</Bubble>
</TouchableOpacity>
)
Thanks in advance.
As a temporary fix, I removed numColums from the flatList and added the following:
contentContainerStyle={{ flexWrap: 'wrap', flexDirection: 'row', width: 345 }}
I would love to be proven wrong here, but as far as I can tell, this cannot be done using numColumns. There is a workaround which I'll list at the end, but first the reasoning:
Explanation
I ran into this same issue but with the footer and did a code dive into the React Native source to see what was happening. First thing I did was use the inspector and I noticed that the header and footer of a FlatList are wrapped in a View while each row of columns is wrapped in CellRenderer > View. This is the first clue that FlatList does not account for headers and footers in numColumns. This is problematic because FlatList does not support masonry type layouts. This hints at the fact that there are many assumptions being made about how they are handling rendering the rows - that is, items are separated into rows to be rendered.
With these clues, I went into the source and found that FlatList passes its own custom renderItem down to VirtualizedList. Meanwhile, ListHeaderComponent and ListFooterComponent are passed down as is. They are never used in FlatList. Not a good sign as you'll see that the aforementioned _renderItem is what handles grouping the items together into columns to render using flexDirection: 'row' and whatever is passed down with columnWrapperStyle.
But perhaps VirtualizedList is smart enough to combine the header and footer into data that gets passed into renderItem?
Sadly, this is not the case. If you follow the code in VirtualizedList, you'll eventually see all the logic get played out in render() where:
a cells array is created
that first has the header pushed into it
followed by all of the data pushed into it via its _pushCells helper method
This is where CellRenderer appears;
hence why headers and footers are not wrapped by this whereas the rows are.
This is also where FlatLists _renderItem is used explaining why you get numColumns number of items wrapped in a CellRenderer.
and then finished with the footer being pushed in the same manner as the header.
This cells array of React components is then eventually cloned which helps with things such as keeping scroll position.
And finally rendered.
Do to this implementation, you will always get a fixed CellRenderer component which prevents headers and footers from being included as part of numColumns.
Workaround (not recommended)
If you've used React Native prior to FlatList being released, you'll know that one old workaround was to be very careful with your dimensions and use flexWrap: 'wrap'. It's actually documented within the source code as it will spit out a warning if you use this method of handling columns. Do note that it is NOT recommended to do this (I believe performance and perhaps scroll position may be some of the reasons against using this method).
If you are willing to do this though, add these styles to your contentContainerStyle:
flexDirection: 'row',
flexWrap: 'wrap',
// You'll probably also want this for handling empty cells at the end:
justifyContent: 'flex-start',
and remove the numColumns prop. Then make sure to manually size your component dimensions to get the correct looking column style layout you desire. This should allow your header and footer to render as part of the columns.
If you want to do it with numOfColumns, than use flexDirection:'row' within your header component
_renderGoalHeader = () => (
return(
<View style={{flexDirection:'row'}}>
<TouchableOpacity
onPress={() => this.openAddGoal()}
style={{ flex:1, padding: 10, }}>
<Bubble style={[styles.newGoal]}>
<Text style={[styles.touchableText]}>New +</Text>
</Bubble>
</TouchableOpacity>
<View>
<View style={{flex:1}}/> //this view is just to cover half width
);
)
While checking out the tutorial here: https://facebook.github.io/react-native/docs/flexbox.html#align-items, I was unable to get the alignItems value to align the rows without any space between when I added flexWrap:'wrap' to the parent view (and enough child views such that it'd wrap). Flexbox acted as if it had a 'space-between' requirement for the rows.
<View style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-start',
flexWrap:'wrap',
alignItems: 'flex-start'
}}>
** Enough Views to get a wrap **
</View>
Setting flex:0 gets me the results I wanted:
The same behavior is expressed when I use flexDirection:'column', except no matter what I set the flex value to, I get the unwanted behavior:
Am I using flexbox incorrectly? Or is this a bug inside of react-native's flexbox?
With the newest version of React Native v0.43.1, this issue is fixed and alignContent is exposed in React Native.
I am using React Native's flexbox (not css flexbox). I am creating an image gallery and the first image has to be double the size, and the rest of the images smaller. Works good, but I have a problem that the third image is displayed in new row, instead where the blank space is.
Is it possible to achieve such behaviour with flex-box, so that the third image would be below the first small image?
I tried all combinations with aligning items, self aligning, flex directions, but no success. If needed I can provide a small example of the code which I already have.
I don't have a fully responsive answer, but this may be helpful here:
<View style={{ flexDirection: 'column' }}>
<View style={{ flexDirection: 'row' }}>
{this.renderPhoto(0)}
<View>
{this.renderPhoto(1)}
{this.renderPhoto(2)}
</View>
</View>
<View style={{ flexDirection: 'row' }}>
{render rest...}
</View>
</View>
Try this component. Maybe it will help you
https://xudafeng.github.io/autoresponsive-react/