React-Native FlatList with 3 cards paging layout
B

2

6

In this snack I am trying to have 3 cards in the center of the screen with a horizontal FlatList and enabled paging to jump to the next 3 cards on scroll.

But the layout starts getting destroyed after scrolling and some pixels of the next/previous card appears in the view.

How should I style this list to always have exactly 3 cards in the center of the screen and scroll will jump to the next page with the next 3 cards ? Or like the GooglePlay store, a fixed pixels of previous/next card be visible to the left and right of the main 3 cards. (Example screenshots below)

 <View style={{flex:1,justifyContent: 'center', marginLeft: 5, marginRight: 5,}}>
      <FlatList
        horizontal
        pagingEnabled
        data={data}
        keyExtractor={(item) => `ìtem-${item}`}
        renderItem={({ item }) => (
          <Card style={{width:Dimensions.get("window").width/3-5,marginRight:5}}>
            {/* some content */}
          </Card>
        )}
      />
 </View>

I do not need a library like snap-carousel or so ...

enter image description here

Bicorn answered 3/9, 2021 at 15:5 Comment(0)
R
10

use Scrollview prop snapToOffsets to achieve that.

like google play example ( one by one ) try snack.

enter image description here

your example ( three by three ) try snack.

enter image description here

how to use snapToOffsets?

const snapToOffsetsLikeGooglePlay = data.map((x, i) => {
    return ((i * itemWidth) + startScroll)
})

const snapToOffsetsLikeYourExample = data.map((x, i) => {
    return ((i * (itemWidth) * previewCount) + startScroll)
})

//see the example below to know 
//what is `startScroll` and `previewCount` mean? 
//and how to calculate `itemWidth`?

here the full example

import React from 'react';
import {FlatList, Text} from 'react-native';
import { View, StyleSheet, ScrollView, Dimensions } from 'react-native';

const { width } = Dimensions.get('window');
//you need to preview n items.
const previewCount = 3;
//to center items
//the screen will show `previewCount` + 1/4 firstItemWidth + 1/4 lastItemWidth 
//so for example if previewCount = 3
//itemWidth will be =>>> itemWidth = screenWidth / (3 + 1/4 + 1/4)
const itemWidth = width/(previewCount + .5);
//to center items you start from 3/4 firstItemWidth 
const startScroll = (itemWidth * 3/4);


const App = () => {

    const data = [...Array(24).keys()];
    const flatlistRef = React.useRef();

    
    React.useEffect(() => {
        if (flatlistRef.current) flatlistRef.current.scrollToOffset({
            offset:startScroll, animated: false
        });
    }, [flatlistRef]);


    const snapToOffsetsLikeGooglePlay = data.map((x, i) => {
        return ((i * itemWidth) + startScroll)
    })

    const snapToOffsets = data.map((x, i) => {
        return ((i * (itemWidth) * previewCount) + startScroll)
    })


    return (
        <FlatList
            ref={flatlistRef}
            style={styles.container}
            pagingEnabled={true}
            horizontal= {true}
            decelerationRate={0}
            snapToOffsets={snapToOffsets}
            snapToAlignment={"center"}
            data={data}
            renderItem={({item, index}) => (
                <View style={styles.view} >
                    <Text style={styles.text}>{index}</Text>
                </View>
            )}/>
    );

}



export default App;


const styles = StyleSheet.create({
    container: {

    },
    view: {
        marginTop: 100,
        backgroundColor: '#eee',
        width: itemWidth - 20, //20 is margin left and right
        margin: 10,
        height: 140,
        borderRadius: 10,
        justifyContent : 'center',
        alignItems : 'center',
    },
    text : {
        fontSize : 60,
        fontWeight : 'bold',
        color : '#aaa',
    },

});

update: start from zero as @Amir-Mousavi comment

one by one try snack
1-) comment useEffect.
2-) set const startScroll = (itemWidth * 3/4)

enter image description here

three by three try snack
1-) comment useEffect.
2-) set const startScroll = (itemWidth * 2.75)

enter image description here

Raddie answered 5/9, 2021 at 20:8 Comment(1)
Very nice, but the list always starts at index 1, and 0 is already passed a cardBicorn
T
3

Ok after much work and testing I finally was able to fix this.

snapToInterval have to snap to interval a full length of the screen.

if you use pWidth *3 it wont work. Now you may ask why, I really do not understand , it may have something to do with float values.

But if you use snapToInterval={Dimensions.get('window').width} it should work.

Have a look at snack example

Tasty answered 5/9, 2021 at 18:32 Comment(2)
Thanks for the answer, but running the snack, the list always jumps to the beggining.Bicorn
Ok friend Was able to pay much more time and testing and was able to fix it. Have a look at my edited answer again.Tasty

© 2022 - 2024 — McMap. All rights reserved.