skip to Main Content

I have a horizontal ScrollView, all items have different widths

Is there a way to scroll one by one, so it would stop in the center of each item?

If the first answer to question is yes, then is there a way to know the index of item (that is centered), so I can change the index of selected dot?

https://snack.expo.dev/@drujik/horizontal-scroll-diff-widths

enter image description here

2

Answers


  1. Example for: https://i.stack.imgur.com/thKLv.gif

    I’m using FlatList and its props.

    More information: https://reactnative.dev/docs/flatlist

    import * as React from "react";
    import { StyleSheet, Dimensions, FlatList, Text, View } from "react-native";
    
    const data = [
      {
        text: "Page1",
        width: 300,
      },
      {
        text: "Page2",
        width: 250,
      },
      {
        text: "Page3",
        width: 200,
      },
    ];
    
    const DOT_SIZE = 8;
    const { width } = Dimensions.get("window");
    
    export default function App() {
      const [indexDot, setIndexDot] = React.useState(0);
    
      const onChangeDot = (event) => {
        setIndexDot(Math.ceil(event.nativeEvent.contentOffset.x / width));
      };
    
      const renderPagination = React.useMemo(() => {
        return (
          <View style={styles.wrapPagination}>
            {data.map((_, index) => {
              return (
                <View
                  key={index}
                  style={[
                    styles.dot,
                    {
                      backgroundColor:
                        indexDot === index ? "#E7537A" : "rgba(0, 0, 0, 0.3)",
                    },
                  ]}
                />
              );
            })}
          </View>
        );
      }, [data?.length, indexDot]);
    
      const renderItem = ({ item }) => (
        <View style={styles.wrapItem}>
          <View
            style={{
              ...styles.item,
              width: item.width,
            }}
          >
            <Text>{item.text}</Text>
          </View>
        </View>
      );
    
      return (
        <>
          <FlatList
            horizontal
            pagingEnabled
            disableIntervalMomentum
            showsHorizontalScrollIndicator={false}
            data={data}
            renderItem={renderItem}
            scrollEventThrottle={200}
            onMomentumScrollEnd={onChangeDot}
          />
          {renderPagination}
        </>
      );
    }
    
    const styles = StyleSheet.create({
      wrapPagination: {
        flexDirection: "row",
        flex: 1,
        justifyContent: "center",
        alignItems: "center",
      },
      dot: {
        height: DOT_SIZE,
        width: DOT_SIZE,
        borderRadius: DOT_SIZE / 2,
        marginHorizontal: 3,
     },
     wrapItem: {
       width,
       padding: 20,
       alignItems: "center",
       justifyContent: "center",
     },
     item: {
       alignItems: "center",
       justifyContent: "center",
       borderWidth: 1,
     },
    });
    
    Login or Signup to reply.
  2. You can achieve this by react-native-snap-carousel and For dot, You can use pagination.

        import Carousel, { Pagination } from 'react-native-snap-carousel';
    
        const [active, setActive] = useState(0)
        const [data, setData] = useState([])
    
        <Carousel
              keyExtractor={(_, index) => `id-${index}`}
              data={data}
              renderItem={renderItem}
              onSnapToItem={setActive} />
                            
        <Pagination
             dotsLength=length}
             activeDotIndex={active}
             dotStyle={{ backgroundColor: colors.blue }}
             inactiveDotStyle={{ backgroundColor: colors.gray }}
             inactiveDotScale={1}
             inactiveDotOpacity={1} />
                             
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search