Daniel Logvin
Daniel Logvin

Reputation: 502

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>

Upvotes: 2

Views: 5619

Answers (3)

Narayen S
Narayen S

Reputation: 9

I tried the answer suggested by @MJ Studio but it did not work out for me, so I tried a work around, I know this is not an ideal solution, but it works for me, hope this is useful to someone else as well.


const renderComponents = () => {
  return (
    <ScrollView>
      <View style={styles.cardwrap}>
        <View style={styles.card}>
          <Text>Hello 1</Text>
        </View>
        <View style={styles.card}>
          <Text>Hello 2</Text>
        </View>
        <View style={styles.card}>
          <Text>Hello 3</Text>
        </View>
        <View style={styles.card}>
          <Text>Hello 4</Text>
        </View>
        <View style={styles.card}>
          <Text>Hello 5</Text>
        </View>
      </View>
    </ScrollView>
  );
};

export default renderComponents;

// . . . . . . . . . Styles . . . . . . . . .

const styles = StyleSheet.create({
  cardwrap: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    justifyContent: 'space-between',
    marginBottom: 30,
    marginHorizontal: 10,
  },

  card: {
    width: '45%',
    backgroundColor: 'red',
    marginVertical: 10,
    paddingVertical: 20,
    alignItems: 'center',
  },
});

In the above mentioned code, I used flexDirection: 'row' to make sure that the cards are sequential and flexWrap: 'wrap' to contain the cards within the view.

Note : Make sure that the card designed is with width which does not span more that 50% or else it would move to the next row.

Sample image of the cards

Upvotes: 0

Mayur Jadhav
Mayur Jadhav

Reputation: 1

You can achieve this using Flatlist numColumn ={2} you can follow my snippets.

    <FlatList
      data={data}
      contentContainerStyle={{alignItems:'center'}}
      columnWrapperStyle={{ flexWrap: 'wrap'}}
      numColumns={2}
      renderItem={({item}) => renderItem(item)}
    />

Upvotes: 0

MJ Studio
MJ Studio

Reputation: 4611

  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

Upvotes: 4

Related Questions