dohooo / react-native-reanimated-carousel

šŸŽ  React Native swiper/carousel component, fully implemented using reanimated v2, support to iOS/Android/Web. (Swiper/Carousel)
https://react-native-reanimated-carousel.vercel.app
MIT License
2.71k stars 313 forks source link

Can't implement infinite scrolling. #306

Open qnrjs42 opened 1 year ago

qnrjs42 commented 1 year ago

Describe the bug A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks!

Hello, dohooo.

Can't implement infinite scrolling. When you try to load data, it moves to the first index. I saved the current index value and specified the index value again when I loaded the data But It's flickering.

To Reproduce Steps to reproduce the behavior:

type 1

  1. go to last index
  2. load data
  3. force go to first index and flicker item

type 2

  1. go to last index
  2. save last index
  3. load data
  4. scrollTo saved index
  5. flicker item

Expected behavior A clear and concise description of what you expected to happen.

Infinite Scrolls.

Screenshots If applicable, add screenshots to help explain your problem.

type 1 video https://user-images.githubusercontent.com/19409518/200150732-b4d31b1c-3ab3-4401-8617-b4e66d056fcc.MP4

type 2 video https://user-images.githubusercontent.com/19409518/200150911-78588bcd-a271-487d-bfb6-2d140f72b18f.MP4

Versions (please complete the following information):

Smartphone (please complete the following information):

Additional context Add any other context about the problem here.

import * as React from 'react';
import {
  StyleSheet,
  Text,
  View,
  ViewProps,
  ViewStyle,
  Dimensions,
  Button,
  type StyleProp,
} from 'react-native';
import Animated, {
  interpolate,
  interpolateColor,
  useAnimatedStyle,
  type AnimateProps,
  type AnimatedStyleProp,
} from 'react-native-reanimated';
import Carousel, { type ICarouselInstance } from 'react-native-reanimated-carousel';
import { LongPressGestureHandler } from 'react-native-gesture-handler';

type TAnimationStyle = (value: number) => AnimatedStyleProp<ViewStyle>;

const { width: WINDOW_WIDTH } = Dimensions.get('window');

function Home() {
  const currentIndexRef = React.useRef<number>(0);
  const carouselRef = React.useRef<ICarouselInstance | null>(null);

  const [dataArr, setDataArr] = React.useState([...new Array(6).keys()]);

  // scrollTo index after data is loaded
  // React.useEffect(() => {
  //   carouselRef.current?.scrollTo({
  //     index: currentIndexRef.current,
  //     animated: false,
  //   });
  // }, [dataArr]);

  const animationStyle: TAnimationStyle = React.useCallback((value: number) => {
    'worklet';

    const zIndex = interpolate(value, [-1, 0, 1], [10, 20, 30]);
    const translateX = interpolate(value, [-2, 0, 1], [-WINDOW_WIDTH, 0, WINDOW_WIDTH]);

    return {
      transform: [{ translateX }],
      zIndex,
    };
  }, []);

  const onLoadData = React.useCallback((): void => {
    setDataArr(prev => [...prev, ...new Array(2).keys()]);
  }, []);

  const onScrollEnd = React.useCallback((index: number): void => {
    currentIndexRef.current = index;
  }, []);

  return (
    <View style={styles.carouselContainer}>
      <Carousel
        ref={carouselRef}
        loop={false}
        key={dataArr.length}
        style={styles.carousel}
        width={WINDOW_WIDTH}
        data={dataArr}
        renderItem={({ index, animationValue }) => {
          return (
            <CustomItem
              key={index}
              index={index}
              animationValue={animationValue}
              dataLength={dataArr.length}
              onLoadData={onLoadData}
            />
          );
        }}
        customAnimation={animationStyle}
        scrollAnimationDuration={1200}
        onScrollEnd={onScrollEnd}
        autoFillData
      />
    </View>
  );
}

interface ItemProps {
  index: number;
  dataLength: number;
  animationValue: Animated.SharedValue<number>;
  onLoadData: () => void;
}
const CustomItem: React.FC<ItemProps> = ({ index, dataLength, animationValue, onLoadData }) => {
  const maskStyle = useAnimatedStyle(() => {
    const backgroundColor = interpolateColor(
      animationValue.value,
      [-1, 0, 1],
      ['#000000dd', 'transparent', '#000000dd'],
    );

    return {
      backgroundColor,
    };
  }, [animationValue]);

  return (
    <View style={{ flex: 1 }}>
      <SBItem
        key={index}
        index={index}
        style={{ borderRadius: 0 }}
        dataLength={dataLength}
        onLoadData={onLoadData}
      />
      <Animated.View
        pointerEvents='none'
        style={[
          {
            position: 'absolute',
            top: 0,
            left: 0,
            right: 0,
            bottom: 0,
          },
          maskStyle,
        ]}
      />
    </View>
  );
};

interface SBItemProps extends AnimateProps<ViewProps> {
  style?: StyleProp<ViewStyle>;
  index: number;
  dataLength: number;
  pretty?: boolean;
  onLoadData: () => void;
}
export const SBItem: React.FC<SBItemProps> = props => {
  const { style, index, pretty, dataLength, onLoadData, ...animatedViewProps } = props;
  const [isPretty, setIsPretty] = React.useState(pretty);
  return (
    <LongPressGestureHandler
      onActivated={() => {
        setIsPretty(!isPretty);
      }}
    >
      <Animated.View style={{ flex: 1 }} {...animatedViewProps}>
        <View style={styles.sbItemContainer}>
          <Text style={styles.sbItemContainerText}>{index + 1}</Text>
          {index === dataLength - 1 ? <Button title='load data' onPress={onLoadData} /> : null}
        </View>
      </Animated.View>
    </LongPressGestureHandler>
  );
};

const styles = StyleSheet.create({
  carouselContainer: {
    flex: 1,
    backgroundColor: 'black',
    justifyContent: 'center',
    alignItems: 'center',
  },
  carousel: {
    width: WINDOW_WIDTH,
    height: 400,
  },
  sbItemContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#fff',
    borderRadius: 8,
    overflow: 'hidden',
  },
  sbItemContainerText: {
    fontSize: 70,
  },
});

export default Home;
dohooo commented 1 year ago

šŸ”“

šŸ‘Øā€šŸ’» I'm so busy recently, so I'm going away for a little while, but I'll come back by the end of this month.

ā™„ļø Rest assured, I love this project, I will not give up.

2022.11.6


GeorgeNiotis commented 1 year ago

any luck with that?