'How to create two columns with space beetwen in react native - flatList

Hi i'm new in React Native.

I am trying to create two columns layout with space beetween using react native component called flatList.

Here is my view Code:

<View style={styles.container}>
        <FlatList
            data={db}
            keyExtractor={ (item, index) => item.id }
            numColumns={2}
            renderItem={
                ({item}) => (
                    <TouchableWithoutFeedback  onPress ={() => showItemDetails(item.id)}>
                        <View style={styles.listItem}>
                            <Text style={styles.title}>{item.name}</Text>
                            <Image
                                style={styles.image}
                                source={{uri: item.image}}
                            />
                            <Text style={styles.price}>{item.price} zł</Text>
                        </View>
                    </TouchableWithoutFeedback>
                )
            }
        />
    </View>

Here is styles:

container: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'space-between',
    padding: 10,
    marginBottom: 40
},
listItem: {
    maxWidth: Dimensions.get('window').width /2,
    flex:0.5,
    backgroundColor: '#fff',
    marginBottom: 10,
    borderRadius: 4,
},

And result is two columns but without space between. Could you help me resolve this problem ?



Solution 1:[1]

You can give the item itself a width value of 45%. Also, flatlist has a property called columnWrapperStyle that you can give the value justifyContent: 'space-between.

Heres an example:

<FlatList
    columnWrapperStyle={{justifyContent: 'space-between'}}
    data={ApiData}
    numColumns={2}
    renderItem={({item}) => {
      return (
         <item style={{width: '45%'}} />
      );
    }}
/>

Solution 2:[2]

Use ItemSeparatorComponent for render a compontent between items

Docs: Rendered in between each item, but not at the top or bottom.

    <FlatList
        data={arrayOfData}
        horizontal
        ItemSeparatorComponent={
            () => <View style={{ width: 16, backgroundColor: 'pink' }}/>
        }
        renderItem={({ item }) => (
            <ItemView product={item} />
        )}
    />

Preview in horizontal list enter image description here

If list is vertical and suppose columnCount is 2

enter image description here

Solution 3:[3]

You have to give the styles.container to the contentContainerStyle propety of Flatlist, like so:

<FlatList
        data={db}
        keyExtractor={ (item, index) => item.id }
        contentContainerStyle={styles.container}
        numColumns={2}
        renderItem={
            ({item}) => (
                <TouchableWithoutFeedback  onPress ={() => showItemDetails(item.id)}>
                    <View style={styles.listItem}>
                        <Text style={styles.title}>{item.name}</Text>
                        <Image
                            style={styles.image}
                            source={{uri: item.image}}
                        />
                        <Text style={styles.price}>{item.price} z?</Text>
                    </View>
                </TouchableWithoutFeedback>
            )
        }
    />

Solution 4:[4]

Just add some margin to the style of the list Item.

listItem: {
  margin: 10,
}

Solution 5:[5]

I haven't used this library, but adding padding: 10 to listItem styles should help.

Solution 6:[6]

Based on your example it looks like you can add a margin to your list item styles:

listItem: {
    maxWidth: Dimensions.get('window').width /2,
    flex:0.5,
    backgroundColor: '#fff',
    marginBottom: 10,
    borderRadius: 4,
    margin: 18,
},

Keep in mind that this is equivalent to doing:

listItem: {
    maxWidth: Dimensions.get('window').width /2,
    flex:0.5,
    backgroundColor: '#fff',
    marginBottom: 10,
    borderRadius: 4,
    marginTop: 18,
    marginBottom: 18,
    marginRight: 18,
    marginLeft: 18,
},

Customize to your liking or spec :)

Solution 7:[7]

Assuming your items are flex:1 and no width specified. You can wrap your renderItem with another view that adds the padding if needed


function columnWrappedRenderItemFunction<ItemT>(
  renderItem: ListRenderItem<ItemT>,
  numColumns: number,
  space: FlatListProps<ItemT>["space"],
  numberOfItems: number
): FlatListProps<ItemT>["renderItem"] {
  return function columnWrappedRenderItem({
    index,
    ...props
  }: Parameters<ListRenderItem<ItemT>>[0]): ReturnType<ListRenderItem<ItemT>> {
    const needsGapOnLeft = index % numColumns !== 0;
    let extraItems = 0;
    if (index === numberOfItems - 1) {
      extraItems = (numColumns - (numberOfItems % numColumns)) % numColumns;
    }
    if (needsGapOnLeft) {
      return (
        <>
          <View style={{width:space}} />
          {renderItem({ index, ...props })}
          {Array.from({ length: extraItems }, (_, k) => (
            <View key={"extra_" + k} style={{marginLeft:space, flex:1}} />
          ))}
        </>
      );
    } else {
      return (
        <>
          {renderItem({ index, ...props })}
          {Array.from({ length: extraItems }, (_, k) => (
            <View key={"extra_" + k} marginLeft={space} style={{flex:1}} />
          ))}
        </>
      );
    }
  };
}

e.g.

function myRenderItem() { ... }
...
return (<FlatList 
   ...
   data={data}
   renderItem={
     numColumns === 1
          ? renderItem
          : columnWrappedRenderItemFunction(
              renderItem,
              numColumns,
              space,
              data.length
            )
      }
   numColumns={numColumns}
   ItemSeparatorComponent={() => <View style={{height: space}} />}
  />);

Solution 8:[8]

How to create two columns with equal spacing between items:

    <FlatList 
        data={DATA}
        renderItem={renderItem}
        keyExtractor={(item) => item.id}
        horizontal={false}   // you must include this line when using numColumns [per the documentation][1]
        numColumns={2}   // creates two columns
        key={2}   // add key to prevent error from being thrown
        columnWrapperStyle={{justifyContent: 'space-between'}}   // causes items to be equally spaced
    >

Also, this will set each column to 1/2 the screen width:

const styles = StyleSheet.create({
item: {
      flex: 1/2,
}})

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Luke Melaia
Solution 2 Sanjeev
Solution 3 Komeyl94
Solution 4 Peyotle
Solution 5 Saleel
Solution 6 TechnoTim
Solution 7 Archimedes Trajano
Solution 8 Green