react-native-reanimated-carousel icon indicating copy to clipboard operation
react-native-reanimated-carousel copied to clipboard

onScrollBegin triggers on single tap but onScrollEnd does not

Open andonovn opened this issue 2 years ago • 10 comments

Hey there, thanks for the nice library ^^

I think the behaviour for onScrollBegin and onScrollEnd should be the same once a user do a single tap on the carousel. Currently, the first one gets executed while the latter is not.

To Reproduce Steps to reproduce the behavior:

  1. Load the Carousel with required data
  2. Add onScrollBegin={() => console.log('start')} onScrollEnd={() => console.log('end')}
  3. Tap on the Carousel
  4. See 'start' but not 'end'

Expected behavior Either both callbacks should be executed, OR neither of the callbacks should not be executed

Versions (please complete the following information):

  • react: v17.0.2
  • react-native: v0.68.2
  • react-native-reanimated: v2.8.0
  • react-native-reanimated-carousel: v3.0.4
  • react-native-gesture-handler: v2.2.1

Smartphone (please complete the following information):

  • Device: iPhone 13 Pro
  • OS: 15.1

Haven't tested on other devices, my blind guess is it will work the same across all the devices but I may be terribly wrong :)

Not sure if this is considered a bug but in our case it is because we use the both callbacks to toggle absolutely positioned elements on the screen, outside the Carousel. Any suggestions for work-arounds are welcomed ^^

andonovn avatar Aug 26 '22 14:08 andonovn

Thanks for your detailed reproduction. I'll check it ASAP .

dohooo avatar Aug 26 '22 15:08 dohooo

Same issue here. :( Did you find any workaround @andonovn?

sylvaindubus avatar Sep 21 '22 07:09 sylvaindubus

I've managed to reproduce the same behavior using onProgressChange:

const [scrolling, setScrolling] = useState(false);

useEffect(() => {
  if (scrolling) {
    // do onScrollBegin stuff
  } else {
    // do onScrollEnd stuff
  }
}, [scrolling]);


const onProgressChange = (_: number, absoluteProgress: number) => {
  if (absoluteProgress % 1 !== 0) {
    setScrolling(true);
  } else {
    setScrolling(false);
  }
}; 

sylvaindubus avatar Sep 21 '22 08:09 sylvaindubus

I'm experiencing this issue as well, for context see SO, where the onScrollBegin and onScrollEnd are used to prevent Pressable child components from being triggered. The onScrollBegin gets triggered at a single tap (expected gesture for Pressing) instead of at actually scrolling (swiping gesture) the carousel.

martwetzels avatar Oct 28 '22 09:10 martwetzels

@martwetzels

This is the exact issue I'm having (even came from the same SO question). Did you end up finding a solution?

davidwagn avatar Dec 22 '22 13:12 davidwagn

@davidwagn not with this library, I ended up implementing something myself that got the job done.

martwetzels avatar Dec 22 '22 14:12 martwetzels

Same issue :( Any solutions?

Vepsur avatar Jan 03 '23 08:01 Vepsur

I'm not sure if this is entirely related, maybe I've missed the point of this thread. My issue was with being able to detect when a user taps a child of the carousel vs swiping through the carousel itself... I wanted to at least put this here to help anyone that needs a solution in the mean time even if it's not ideal...

I ended up having to use state to track when a child item is pressed and checked the change in x movement on the onPressOut event to be able to detect pressing children vs swiping through the carousel...

const MyComponent = () => {
    const [pressState, setPressState] = useState({});
    return (
        <Carousel
            ...
            renderItem={({ index }) => (
                <Pressable
                  onPressIn={(event) => {   
                    setPressState({
                      ...pressState,
                      [index]: event.nativeEvent.pageX,
                    });
                  }}
                  onPressOut={(event) => {
                    const delta = event.nativeEvent.pageX - pressState[index] || 0;
                    if (Math.abs(delta) < 5) {
                      // handle item pressed here
                    }
                  }}
                  key={index}
                >
                  {/* Child Item */}
                </Pressable>
              )}
        />
    )
}

AlexanderCollins avatar Jan 08 '23 05:01 AlexanderCollins

I'm experiencing the same/similar issue. I'm not using onScrollBegin or onScrollEnd but on app launch the first attempt to swipe the carousel left/right results in the child (card) receiving a touch event. This only happens on first swipe try after launch. It never happens again until next app launch.

Here's my carousel. The presence of onProgressChange does not make a difference.

      <Carousel
        ref={carouselRef}
        data={cards}
        renderItem={renderCard}
        loop={false}
        width={viewport.width}
        style={{ overflow: 'visible' }}
        onProgressChange={() => {
          if (carouselRef.current) {
            const currentSlide = carouselRef.current.getCurrentIndex();
            if (currentSlide !== activeSlideRef.current) {
              activeSlideRef.current = currentSlide;
              onScrollIndexChanged(currentSlide);
            }
          }
        }}
      />

ajp8164 avatar Jan 20 '23 19:01 ajp8164

const animationState = useRef({ shouldBeFinished: false, started: false, });

  <Carousel
    ....
    onScrollEnd={() => {
    if (animationFinished && animationStarted) {
      animationState.current.shouldBeFinished = true;
    }
  }}
  onProgressChange={() => {
    if (animationFinished && animationStarted) {
      if (animationState.current.shouldBeFinished) {
        animationFinished();
        animationState.current.shouldBeFinished = false;
        animationState.current.started = false;
      } else if (!animationState.current.started) {
        animationStarted();
        animationState.current.started = true;
      }
    }
  }}
  />

MatLish00010 avatar Aug 22 '23 18:08 MatLish00010