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.86k stars 329 forks source link

Fire event when scrolling past? #711

Open bobbyziom opened 1 month ago

bobbyziom commented 1 month ago

Working with the circlular carousel, and I'm missing one feature

Wondering if there is a way to fire an event (e.g. haptic) when an item is passing by the center.

I've tried both onScrollEnd and ProgressChange trying to convert the absolute valute to index and then firing. But when scrolling faster it seems to not be possible.

Basically just the implementation from examples im playing with atm.

<Carousel
                  ref={ref}
                  width={itemSize}
                  height={itemSize}
                  style={{
                    width: UI_CONSTANTS.screenWidth,
                    height: UI_CONSTANTS.screenWidth / 2,
                  }}
                  onProgressChange={onProgressChange}
                  onScrollEnd={onSnapToItem}
                  snapEnabled
                  pagingEnabled={false}
                  overscrollEnabled={false}
                  scrollAnimationDuration={200}
                  data={data || []}
                  renderItem={({ item, index }) => (
                    <Pressable
                      key={item._id}
                      onPress={() => onItemPress(index)}
                      style={{ flex: 1 }}
                    >
                      <View
                        style={{
                          backgroundColor: 'black',
                          flex: 1,
                          borderRadius: 100,
                          justifyContent: 'center',
                          overflow: 'hidden',
                          alignItems: 'center',
                          borderWidth: 2,
                          borderColor: palette.primary[500],
                        }}
                      >
                        <View style={{ width: '100%', height: '100%' }}>
                          <SlideItem index={index} source={{ uri: item.imageLogo }} />
                        </View>
                      </View>
                    </Pressable>
                  )}
                  customAnimation={animationStyle}
                />
DanielProode commented 2 weeks ago

I solved it with useAnimatedReaction.

const scrollPosition = useSharedValue(0);
let centeredElement: number | undefined;

const onCenterItemChange = (currentIndex: any) => {
  if (centeredElement != currentIndex) {
    Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Soft)
    centeredElement = currentIndex;
     }};

useAnimatedReaction(
    () => Math.round(scrollPosition.value),
    (currentIndex) => {
        runOnJS(onCenterItemChange)(currentIndex);
    },
    [scrollPosition] );

  <Carousel
  ...
  onProgressChange={(_, absoluteProgress) => {
     scrollPosition.value = absoluteProgress;
      }}>
  ...