react-responsive-carousel icon indicating copy to clipboard operation
react-responsive-carousel copied to clipboard

Vertical scroll on on mobile affects changes the slide

Open AnushHakobyan opened this issue 5 years ago • 21 comments

Hi all. I want to submit an issue. When carousel is opened on a mobile, on android/chrome for example, vertical swiping on mobile screen causes carousel slide to be changed: swiped to next or prev.

AnushHakobyan avatar Sep 03 '19 13:09 AnushHakobyan

The same thing happens if you want to do up/down scroll(not a perfect straight line), it will register as left/right as well.

jiferent avatar Dec 20 '19 18:12 jiferent

Having the same issue .

Marguelgtz avatar Jan 26 '20 18:01 Marguelgtz

I have this problem as well.

amarklars avatar Feb 06 '20 09:02 amarklars

I am also having the same issue..

sathya1690 avatar Feb 10 '20 12:02 sathya1690

Same here

DenisCangemi avatar Feb 14 '20 09:02 DenisCangemi

Same. Also getting an err: react-swipe.js:226 [Intervention] Ignored attempt to cancel a touchmove event with cancelable=false, for example because scrolling is in progress and cannot be interrupted. ¯_(ツ)_/¯

swedenSnow avatar Feb 25 '20 10:02 swedenSnow

To anyone having this issue, I've submitted a PR to the react-easy-swipe repo (also managed by leandrowd) to fix the error message mentioned by @swedenSnow, so you can look at that if you want it to stop spitting out the error, but if you want to stop the vertical swipes from switching the panels there is a prop on the carousel swipeScrollTolerance which takes a number (default is 5) to affect the sensitivity of scrolls till a swipe is created (my testing found 30 to be a good value, YMMV).

kieran-osgood avatar Apr 12 '20 12:04 kieran-osgood

Hello, I think that the transform CSS property should not happen if the swipe is kind of up and down...I've set the swipeScrollTolerance to 100...which indeed is preventing the slide switch from happening on touch end. The problem is that while touch move is active and you're swiping up or down but not perfectly up or down...the next or previous slide still show up a little until you release the touch.

So I think as long as the intent of the touch is up/down the transition should not even begin. You are probably checking the swipeScrollTolerance only on touch end....but by then the transform CSS property already happened.

ovidiudinu avatar May 14 '20 16:05 ovidiudinu

same

mindfulme avatar Aug 11 '20 15:08 mindfulme

swipeable={false} since nothing else helps.

mindfulme avatar Aug 11 '20 15:08 mindfulme

I am encountering the same issue. As a temporary fix, I am using the following:

let [swipeable, setSwipeable] = useState(true);

useEffect(() => {
        if (images.length) {
            function disableScroll() {
                let carousel = document.querySelector('.carousel');

                let startPos;
                let endPos;
                let isScrolling = 1;

                function touchMove(e) {
                    if (
                        e.targetTouches.length > 1 ||
                        (e.scale && e.scale !== 1) ||
                        !startPos
                    )
                        return;

                    var touch = e.targetTouches[0];

                    endPos = {
                        x: touch.pageX - startPos.x,
                        y: touch.pageY - startPos.y
                    };
                    isScrolling =
                        Math.abs(endPos.x) <= Math.abs(endPos.y)
                            ? 1
                            : 0; //When isScrolling is 1, it means vertical sliding and 0 is horizontal sliding
                    if (isScrolling && swipeable) {
                        setSwipeable(false);
                    }
                }

                function touchEnd() {
                    setSwipeable(true);
                    carousel.removeEventListener(
                        'touchmove',
                        touchMove
                    );
                }

                function touchStart(e) {
                    var touch = e.targetTouches[0]; //The touches array object gets all the touches on the screen, taking the first touch
                    startPos = {
                        x: touch.pageX,
                        y: touch.pageY
                    };

                    carousel.addEventListener('touchmove', touchMove);
                }

                carousel.addEventListener('touchstart', touchStart);
                carousel.addEventListener('touchend', touchEnd);
            }


            disableScroll();
        }
    }, [images, swipeable]);
{!!images.length && (
 <Carousel
      swipeable={swipeable}
      showThumbs={false}
      swipeScrollTolerance={30}
 >
     {images.map(renderImage)}
</Carousel>
)}

It does make the scroll lag but works quite well on the production build in iOS. Not tested on Android

ghariosk avatar Nov 04 '20 16:11 ghariosk

Same problem

wulinjie122 avatar Feb 27 '21 15:02 wulinjie122

same :)

fidelusp avatar Mar 11 '21 08:03 fidelusp

You can use preventMovementUntilSwipeScrollTolerance prop with swipeScrollTolerance={100}.

franciscobaaldev avatar May 31 '21 10:05 franciscobaaldev

@ghariosk Thank you for the script. I encountered an issue when swipable set to false, touchEnd function won't call, and it causes next swipe to be disabled. I modified the script a little to fix that issue, and also made it less laggy.

  const [ swipeEnabled, setSwipeEnabled ] = useState(true)
  const [ touchEventsSet, setTouchEventsSet ] = useState(false)
  const swipeScrollTolerance = 30

  useEffect(() => {
    if (images.length) {
      const disableScroll = () => {
        let carousel = document.querySelector('.carousel')

        let startPos
        let endPos
        let isScrolling
        let passedSwipeScrollTolerance = false

        function touchMove(e) {
          if (
            e.targetTouches.length > 1 ||
            ( e.scale && e.scale !== 1 ) ||
            !startPos
          ) {
            return
          }

          if (!passedSwipeScrollTolerance && swipeEnabled) {
            const touch = e.targetTouches[ 0 ]
            endPos = {
              x: Math.abs(touch.pageX - startPos.x),
              y: Math.abs(touch.pageY - startPos.y),
            }
            passedSwipeScrollTolerance = endPos.x > swipeScrollTolerance

            isScrolling = endPos.x < endPos.y //When isScrolling it means vertical sliding
            if (isScrolling) {
              setSwipeEnabled(false)
            }
          }
        }

        function touchEnd() {
          setSwipeEnabled(true)
          passedSwipeScrollTolerance = false
          carousel.removeEventListener('touchmove', touchMove)
        }

        function touchStart(e) {
          const touch = e.targetTouches[ 0 ] //The touches array object gets all the touches on the screen, taking the first touch
          startPos = {
            x: touch.pageX,
            y: touch.pageY,
          }

          carousel.addEventListener('touchmove', touchMove)
        }

        if (!touchEventsSet) {
          carousel.addEventListener('touchstart', touchStart)
          carousel.addEventListener('touchend', touchEnd)
          setTouchEventsSet(true)
        }

        if (!swipeEnabled) {
          setSwipeEnabled(true)
          passedSwipeScrollTolerance = false
        }
      }

      disableScroll()
    }
  }, [ images, swipeEnabled ])
{Boolean(images.length) && (
 <Carousel
      swipeable={swipeEnabled}
      showThumbs={false}
 >
     {images.map(renderImage)}
</Carousel>
)}

dakicnikola avatar Jul 14 '21 09:07 dakicnikola

I am still not able to solve this issue, can someone help me out here?

abhijeetvermayash avatar Nov 01 '21 15:11 abhijeetvermayash

You can use preventMovementUntilSwipeScrollTolerance prop with swipeScrollTolerance={100}.

This actually works like a charm. Thank you.

edwardvinobox avatar Nov 03 '21 20:11 edwardvinobox

same problem

amerzur avatar Nov 07 '21 19:11 amerzur

You can use preventMovementUntilSwipeScrollTolerance prop with swipeScrollTolerance={100}.

I did this, it work. But if you set infiniteLoop on. Then when just did a small swipe (less than 100) by start touching on the left of the first item. It'll scroll 1 round and back to the item. It should do nothing in this case.

Thanks for all your helps if you faced this issue.

ducduan avatar Nov 24 '21 05:11 ducduan

Is this issue fixed?

FruitBro avatar Mar 17 '22 13:03 FruitBro

You can use preventMovementUntilSwipeScrollTolerance prop with swipeScrollTolerance={100}.

worked for me, thanks!

BhavyaCodes avatar Mar 30 '22 06:03 BhavyaCodes

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Sep 27 '22 13:09 stale[bot]

I have the same problem, I can't disable the vertical swipe so that the user can scroll the webpage very well

bayonmbayo avatar Oct 24 '22 00:10 bayonmbayo

preventMovementUntilSwipeScrollTolerance

@ducduan Thanks for the solution it is working for me.

paramkeshkamat avatar Oct 09 '23 06:10 paramkeshkamat