DEV Community

Cover image for Implementing a Tiles View in React Native (a la iOS)
Emilio Srougo
Emilio Srougo

Posted on

Implementing a Tiles View in React Native (a la iOS)

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:

tpr = 3: tpr = 3
tpr = 2: tpr = 2

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!

Latest comments (0)