I recently had a react-native project where a certain screen had the following requirements:
- A screen with square tiles arranged with equal space among them.
- The arrangement must always be from left to right (and look kind of like an iOS home screen).
- The number of tiles per row must be configurable. The size and margin must be calculated accordingly.
This was one occasion where flex was clearly not enough, so after a lot of experimentation, I came up with the following formula:
// tpr = tiles per row
const calcTileDimensions = (deviceWidth, tpr) => {
const margin = deviceWidth / (tpr * 10);
const size = (deviceWidth - margin * (tpr * 2)) / tpr;
return { size, margin };
};
This function, along with the right styles (which I'll show you) provides the expected results. Look at these images:
Here is a full usage example:
import React, { Component } from 'react';
import { Text, View, StyleSheet, Dimensions } from 'react-native';
const { width } = Dimensions.get("window");
export default class App extends Component {
render() {
const tileDimensions = calcTileDimensions(width, 2) // -> change this number and see!
const tiles = 'Lorem Ipsum Dolor Sit Amet'.split(' ')
return (
<View style={styles.container}>
{tiles.map(i => Item({...tileDimensions, text: i}))}
</View>
);
}
}
const Item = ({size, margin, text}) => (
<View style={[styles.item, {width: size, height: size, marginHorizontal: margin}]}>
<Text style={styles.itemText}>{text}</Text>
</View>
)
const calcTileDimensions = (deviceWidth, tpr) => {
const margin = deviceWidth / (tpr * 10);
const size = (deviceWidth - margin * (tpr * 2)) / tpr;
return { size, margin };
};
const styles = StyleSheet.create({
container: {
justifyContent: "flex-start", flexDirection: "row", flexWrap: "wrap", marginTop: 30
},
item: {
backgroundColor: 'yellow',
alignSelf: "flex-start",
alignItems: 'center',
justifyContent: 'center',
marginBottom: 20
},
itemText: {
fontSize: 20
}
});
And, here it is as a Snack in Expo. Feel free to play around with it!
I hope you find this useful. Thanks for reading!
Top comments (0)