Ivan Burzakovskyi
Ivan Burzakovskyi

Reputation: 695

Display images in FlatList

I'm trying to render images in grid view using FlatListbut have faced with the next issue:

My code snippet:

...
renderItem = ({item}) => {
        return (
        <Image source = {{uri: item.photoUrl[0].photoUrl}} style = {{margin: 1,
                                                                    height: Dimensions.get('window').width / 3,
                                                                    width: Dimensions.get('window').width / 3,
                                                                    resizeMode: 'cover'}}
        />
    )
}

render() {
    if(this.props.viewOption === 'grid') {
        return <FlatList
                    data = {this.state.photosKeysArray}
                    keyExtractor={(item, index) => item.id}
                    numColumns = {3}
                    renderItem={this.renderItem}
                />
    } ...

Problem is that FlatList should calculate width of item by itself according to numColumns, right? So in Image I should specify only height. Since I want to render square images, I assign to height a value equals to Dimensions.get('window').width/3, where 3 is value of numColumns.

After that FlatList renders blank spaces instead of images.

If I add width property to Image (like in my code snippet) and define it as height (square image, remember?) then FlatList renders 3 columns with square images but they are show like on my sketch (two full images and the last column is cut):

enter image description here

How to show three full columns?

Upvotes: 8

Views: 26896

Answers (3)

RegularGuy
RegularGuy

Reputation: 3686

Do you want easy squares? , ok then you should know this property that react native has, it's called Aspect Ratio , you just set the width or height, set the aspect ratio to 1 in style and you have an square.

This stays the same

<FlatList
   numColumns={3}
   data={this.state.data}
   renderItem={({ item }) => this.renderItem(item)}
/>

but this is more simple

renderItem(item) {
    return (
        <TouchableOpacity  
                 style={{flex:1/3, //here you can use flex:1 also
                 aspectRatio:1}}>
                <Image style={{flex: 1}} resizeMode='cover' source={{ uri:  item.photoUrl[0].photoUrl}}></Image>
        </TouchableOpacity>
    )
}

It shoud be noted that if you have an extra item below all the rows, and you use flex:1 instead of flex:1/3 it's gonna be a big , really big square, for that you can use the methods described here

Upvotes: 19

Ivan Burzakovskyi
Ivan Burzakovskyi

Reputation: 695

The issue was solved using the next values of width and height of image:

height: (Dimensions.get('window').width - (30 + 2*this.state.columns)) / this.state.columns,
width: (Dimensions.get('window').width - (30 + 2*this.state.columns)) / this.state.columns,

Where 30 is double (left and right) margin of the main screen and 2 is double margin of the image.

Upvotes: 0

Harshal Valanda
Harshal Valanda

Reputation: 5451

numColumns

Multiple columns can only be rendered with horizontal={false}

<FlatList
   numColumns={3}
   data={this.state.data}
   renderItem={({ item }) => this.renderItem(item)}
/>

renderItem

Setup Item (flex / width / height) as per requirement

renderItem(item) {
    return (
        <TouchableOpacity>
            <View style={{
                width: (Constant.SCREEN.width - 32) / 3,
                height: (Constant.SCREEN.width - 32) / 3,
                justifyContent: 'center'
            }}>
                <Image style={{ width: '70%', height: '70%', alignSelf: 'center' }} resizeMode='contain' source={{ uri: item.image }}></Image>
                <SPText
                    style={{ flex: 1.0, textAlign: 'center', marginLeft: 4, marginRight: 4 }}
                    text={item.text}
                    fontSize={10}
                    textColor='white' />
            </View>
        </TouchableOpacity>
    )
}

Upvotes: 4

Related Questions