Search code examples
react-nativeflexbox

How to place 2 cards per row with flex


I'll provide images of what I'm trying to perform:

One that is how I want it to be and one that shows the problem, finally I'll show the code.

First image (how I want it to be):

What I want

Second image (how it looks when I have a third card)

The problem

Here is the code:

<ScrollView>
    <View style={{ padding: 10 }}>
        <View style={{ paddingTop: '5%' }}></View>
        <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>

            {this.state.subjects.map(subject => {
                return (
                    <View key={subject.id}>
                        <TouchableOpacity onPress={() => this.props.navigation.navigate('ViewSubject', { id: subject.id })}>
                            <ImagedCarouselCard
                                width={180}
                                height={180}
                                text={subject.name}
                                shadowColor="#051934"
                                source={{
                                    uri: "http://site.test/" + subject.icon,
                                }}
                            />
                        </TouchableOpacity>
                    </View>
                )
            })}
        </View>
        <View style={{ paddingTop: '2%' }}></View>
    </View>
</ScrollView>

Solution

    1. Set flexWrap to wrap in Container style
    2. Set width of each cards to (screen width - card margin * 3) / 2

    This is my functional component example

    But using FlatList and set numColumns to 2 is more useful FlatList numColumn

    enter image description here

    const subjects = [
        { id: 1, name: 'Card 1' },
        { id: 2, name: 'Card 2' },
        { id: 3, name: 'Card 3' },
        { id: 4, name: 'Card 4' },
      ];
    
      const cardGap = 16;
    
      const cardWidth = (Dimensions.get('window').width - cardGap * 3) / 2;
    
      return (
        <ScrollView>
          <View
            style={{
              flexDirection: 'row',
              flexWrap: 'wrap',
              justifyContent: 'center',
            }}
          >
            {subjects.map((subject, i) => {
              return (
                <View
                  key={subject.id}
                  style={{
                    marginTop: cardGap,
                    marginLeft: i % 2 !== 0 ? cardGap : 0,
                    width: cardWidth,
                    height: 180,
                    backgroundColor: 'white',
                    borderRadius: 16,
                    shadowOpacity: 0.2,
                    justifyContent: 'center',
                    alignItems: 'center',
                  }}
                >
                  <TouchableOpacity>
                    <Text>{subject.name}</Text>
                  </TouchableOpacity>
                </View>
              );
            })}
          </View>
        </ScrollView>
      );
    

    You can see flexWrap docs

    enter image description here