Reputation: 825
I'm trying to do a two column layout in React Native from a list of items. It only seems to work if I define the width of the items, I would like to define just a percentage of the parent width (0.5 would make a 2 column layout, but 0.25 would make a 4 column one). Can this be done?
export default class App extends Component {
render() {
return (
<View style={[styles.container, {width:width}]}>
<View style={styles.item}><Text>{'item1'}</Text></View>
<View style={styles.item}><Text>{'item2'}</Text></View>
<View style={styles.item}><Text>{'item3'}</Text></View>
<View style={styles.item}><Text>{'item4'}</Text></View>
<View style={styles.item}><Text>{'item4'}</Text></View>
<View style={styles.item}><Text>{'item5'}</Text></View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
},
item :{
flex: 0.5, //why this doesnt work???
// width: 150, //using fixed item width instead of flex: 0.5 works
height: 100,
padding: 10,
backgroundColor: 'red',
// flexGrow: 1,
// flexShrink: 0,
}
});
You can play with it here: https://snack.expo.io/SyBjQuRxm
Css working equivalent: https://codepen.io/klamping/pen/WvvgBX?editors=110
Obviously I could do something like creating a container for each column, but that's not the point:
render() {
return (
<View style={[styles.container, {width:width}]}>
<View style={styles.column1}>
<View style={styles.item}><Text>{'item1'}</Text></View>
<View style={styles.item}><Text>{'item2'}</Text></View>
<View style={styles.item}><Text>{'item3'}</Text></View>
</View>
<View style={styles.column2}>
<View style={styles.item}><Text>{'item4'}</Text></View>
<View style={styles.item}><Text>{'item4'}</Text></View>
<View style={styles.item}><Text>{'item5'}</Text></View>
</View>
</View>
);
}
Upvotes: 51
Views: 104505
Reputation: 2144
If a nested flatList is being used because of the numberColumns. I'd suggest using a custom Grid component instead of nesting flat lists because of CPU usage will increase nesting scroll views.
Example of performance comparison between using nested flat list VS using custom grid and paginating the list.
Example using nested flatList for getting 2 columns https://snack.expo.dev/@ronicesarrc/flatlist-with-flatlist-grid-nested
Example using custom grid with 2 columns https://snack.expo.dev/@ronicesarrc/flatlist-with-custom-grid
// Custom grid with 2 columns
const ProductGrid = ({ products, numColumns = 2 }) => {
return (
<View>
{products.map((_, index) => (
index % numColumns === 0 && (
<View key={index} style={{ flexDirection: 'row' }}>
{products.slice(index, index + numColumns).map((prod) => (
<ProductItem key={prod.id} {...prod} />
))}
</View>
)
))}
</View>
);
};
Upvotes: 0
Reputation: 560
you can try scrollview with flatlist. the code below generates 2 columns. if you want 3 columns change numcolumn={data.length/3} etc.
<ScrollView
horizontal
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
contentContainerStyle={{
flexDirection: "row",
flexWrap: "wrap",
}}
>
<FlatList
data={data}
renderItem={this.renderItem}
keyExtractor={(item) => `${item.id}`}
showsHorizontalScrollIndicator={false}
numColumns={data.length / 2}
/>
</ScrollView>
Upvotes: 7
Reputation: 1323
You could map the list of element into a an array of pairs.
Then render the pairs as a row inside a list
<View className="px-4 ">
{Buttons.map((row, i) => {
return (
<View className="flex-1 flex-row" key={i}>
{row.map((item, j) => {
return <ThumbButton key={j} {...item} />;
})}
</View>
);
})}
</View>
For making the nested array you could use this function https://stackoverflow.com/a/44937519/1807666
function combineTwo(inputArray: Array<object>) {
var result = [];
for (var i = 0; i < inputArray.length; i += 2) {
result.push([inputArray[i], inputArray[i + 1]]);
}
return result;
}
Upvotes: 1
Reputation: 6379
It is possible if you use percentage values for the widths:
<View style={styles.container}>
<View style={styles.item}>
...
</View>
</View>
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'flex-start' // if you want to fill rows left to right
},
item: {
width: '50%' // is 50% of container width
}
})
Upvotes: 138