Shaban
Shaban

Reputation: 334

FlatList Horizontal make two items in a column in a row

Just a little styles guidance required. what i need is to make horizontal flat list in which 1st item should be large in height and then other items should be 2 in columns and so on.

i am attaching the images what i have now and what i want.

What i achieved

enter image description here

What i want

enter image description here

And my code

<FlatList
                    horizontal
                    data={this.state.entries}
                    showsHorizontalScrollIndicator={false}
                    contentContainerStyle={{
                    }}
                    renderItem={({ item: rowData }) => {
                        return (
                            <TouchableOpacity
                                key={rowData.title} onPress={() => alert(rowData.title)}>
                                <Card>
                                    <CardItem cardBody>
                                        <Image source={{ uri: rowData.ImagePath }}
                                            style={{
                                                height: (rowData.id == 1 ? 200 : 90),
                                                width: (rowData.id == 1 ? 200 : 150),
                                                flex: 1
                                            }} />
                                    </CardItem>
                                </Card>
                            </TouchableOpacity>
                        );
                    }}
                    keyExtractor={(item, index) => index.toString()}
                />

Anyone help me out. Much appreciated.

Thanks

Upvotes: 1

Views: 8864

Answers (3)

Muhamet Smaili
Muhamet Smaili

Reputation: 383

Actually, I could not find an exact way to do it without modifying data until now.

So basically you need to modify your data from a one-dimensional array to two dimensional and print the data. Check this snack someone implemented a two-dimensional horizontal scroll

I will write for you a function on how to convert the data from one dimensional to two. And you can use it in your project.

const convertToTwoDimesional = (data) => {
    const newData = [];

    for (let index = 0; index < data.length; index += 2) {
      newData.push(data.slice(index, index + 2));
    }
    return newData;
};

So you can use my function to convert your incoming data to two-dimension, and implement the slack from the link.

If you have any questions please ask.


This answers your question, I do not have any information for a better approach, if you have found any, then please tell me.

PS:

This video also explains good flat-list

** Here is the method implemented in Typescript **

function convertToTwoDimensional<T>(data: Array<T>): T[][] {
    const newData = [];
    for (let index = 0; index < data.length; index += 2) {
      newData.push(data.slice(index, index + 2));
    }
    return newData;
}

Upvotes: 0

Andrew
Andrew

Reputation: 28539

Unfortunately, as you may have already guessed the numColumns prop will only work on a vertical FlatList.

Multiple columns can only be rendered with horizontal={false} and will zig-zag like a flexWrap layout. Items should all be the same height - masonry layouts are not supported.

The only way to achieve what you want is to combine the items after the first into groups of two.

So if you had an data set like this

let data = [
  { text: 'one' },
  { text: 'two' },
  { text: 'three' },
  { text: 'four' },
  { text: 'five' },
  { text: 'six' }
]

You would need to convert it into something like this, you don't have to do it like this, it is really up to you but this is one possible way.

let data = [
  { text: 'one' },
  { item1: { text: 'two' }, item2: { text: 'three' } },
  { item1: { text: 'four' }, item2: { text: 'five' } },
  { item1: { text: 'six' }},
]

Combining the items into groups of two means that you can fake that you have a grid layout.

Then all the magic happens in your renderItem function. There if the index is 0, you can show your big image, and then if it isn't you can show the smaller images.

Here is some sample code that should help you understand what I am talking about.

import React, {Component} from 'react';
import { View, StyleSheet, Text, FlatList } from 'react-native';
export default class Screen1 extends React.Component {

  state = {
    data: [
      { text: 'one' },
      { item1: { text: 'two' }, item2: { text: 'three' } },
      { item1: { text: 'four' }, item2: { text: 'five' } },
      { item1: { text: 'six' }},
    ]
  }

  renderItem = ({item, index}) => {
    if (index === 0) {
      return (
        <View style={styles.bigSquare}>
          <Text>{item.text}</Text>
        </View>
      )
    } else {
      return (
        <View>
          <View style={styles.smallSquare}>
            <Text>{item.item1.text}</Text>
          </View>
          {item.item2 && <View style={[styles.smallSquare, {backgroundColor: 'red'}]}>
            <Text>{item.item2.text}</Text>
          </View>}
        </View>
      )
    }
  }

  keyExtractor = (item, index) => `${index}`;

  render() {
    return (
      <View style={styles.container}>
        <FlatList 
          horizontal={true}
          data={this.state.data}
          renderItem={this.renderItem}
          keyExtractor={this.keyExtractor}
        />
      </View>
    )
  }
}


const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  bigSquare: {
    height: 220, 
    width: 220, 
    margin: 10, 
    backgroundColor: 'yellow', 
    justifyContent: 'center', 
    alignItems: 'center'
  },
  smallSquare: {
    height: 100, 
    width: 100, 
    margin: 10, 
    backgroundColor: 'green', 
    justifyContent: 'center', 
    alignItems: 'center'
  }
});

Here it is in a snack https://snack.expo.io/@andypandy/horizontal-flatlist-with-grid

Upvotes: 1

josecastillo86
josecastillo86

Reputation: 330

I hope this helps:

<FlatList
      horizontal
      data={this.state.entries}
      contentContainerStyle={{ flexWrap: "wrap", flexDirection: "column" }}
      renderItem={({ item: rowData }) => {
            return (
                 <TouchableOpacity>
                      <Card>
                          <CardItem cardBody>
                               <View
                                 style={{
                                        height: rowData.id == 1 ? 200 : 90,                                                                                
                                        width: rowData.id == 1 ? 200 : 150,
                                        borderWidth: 1,
                                  }}
                             />
                        </CardItem>
                    </Card>
               </TouchableOpacity>
              );
          }}
/>

Upvotes: 1

Related Questions