Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(iOS) velocityX of PanGestureHandler is always 0 because of gestureRecognizer #972

Open
dprevost-LMI opened this issue Feb 21, 2025 · 2 comments

Comments

@dprevost-LMI
Copy link

dprevost-LMI commented Feb 21, 2025

Environment

React native 73 with react-native-pager-view version 6.2.0 required by react-native-tab-view.
iOS 17 or 18

Description

I’m using the react-native-gesture-handler/PanGestureHandler and react-native/Animated.View to have a swipeable card where, when doing a left swipe, it shows a button under the card at the right. After upgrading to react-native-pager-view version 6.2.0 on iOS, the behaviour started failing. When doing horizontal swipes on my card, the event.nativeEvent.velocityX was always 0 from the onHandlerStateChange of the PanGestureHandler, so I was not able to recognize the left-right swipe.

This PR sounds related to that failure. Using a patch, I removed the gestureRecognizer, and it fixed my issue. I’m not sure I fully understand the why, though since I’m no iOS pro. I also observed that only a press seems possible, no swipe

Reproducible Demo

Used lib

"react-native": "0.73.9"
"react-native-reanimated": "3.16.6",
"react-native-screens": "3.35.0",
"react-native-pager-view": "6.2.0",
"react-native-tab-view": "3.1.1",

Snippet:

  const minDist = 40;
  const activeOffsetX: [number, number] = [-minDist, minDist];

  const onHandlerStateChange = (event: PanGestureHandlerStateChangeEvent) => {
    console.log('event.nativeEvent.velocityX', event.nativeEvent.velocityX);
  };
  const topLayerAnimatedStyle = [{ zIndex: 1 }, { transform: [{ translateX }] }];
  const onGestureEvent = (event: PanGestureHandlerGestureEvent) => {
    dragX.setValue(event.nativeEvent.translationX + offsetX);
  };

  return (
    <>
      <PanGestureHandler
        activeOffsetX={activeOffsetX}
        onGestureEvent={onGestureEvent}
        onHandlerStateChange={onHandlerStateChange}
      >
        <Animated.View style={topLayerAnimatedStyle}>{children}</Animated.View>
      </PanGestureHandler>
    </>
  );

With my patch or on version 6.1.4 my output is:

 LOG  event.nativeEvent.velocityX 0
 LOG  event.nativeEvent.velocityX -1002.9360699191757
 LOG  event.nativeEvent.velocityX -245.47632455384255
 LOG  event.nativeEvent.velocityX 0
 LOG  event.nativeEvent.velocityX -1249.3361543957585
 LOG  event.nativeEvent.velocityX -63.76235796194474
 LOG  event.nativeEvent.velocityX 0
 LOG  event.nativeEvent.velocityX -2644.1441499830335
 LOG  event.nativeEvent.velocityX -16.774982503172016
 LOG  event.nativeEvent.velocityX 0
 LOG  event.nativeEvent.velocityX -581.1156704515844
 LOG  event.nativeEvent.velocityX -20.014514665633452
 LOG  event.nativeEvent.velocityX 0
 LOG  event.nativeEvent.velocityX -1642.6676575322836
 LOG  event.nativeEvent.velocityX -36.247993423507644
 LOG  event.nativeEvent.velocityX 0
 LOG  event.nativeEvent.velocityX 2148.9406521571445
 LOG  event.nativeEvent.velocityX 820.4758208075385
 LOG  event.nativeEvent.velocityX 0
 LOG  event.nativeEvent.velocityX -977.1913252058387
 LOG  event.nativeEvent.velocityX -117.93175092593243

After upgrading to 6.2.0 or without my patch, I have the below output, and the swipe does not work; only the press seems to occur, explaining why I have less output than above.

 LOG  event.nativeEvent.velocityX 0
 LOG  event.nativeEvent.velocityX 0
 LOG  event.nativeEvent.velocityX 0
 LOG  event.nativeEvent.velocityX 0
 LOG  event.nativeEvent.velocityX 0
 LOG  event.nativeEvent.velocityX 0

Note: I tried upgrading to "react-native-tab-view": "4.0.5", but it did not fix the issue!

@dprevost-LMI dprevost-LMI changed the title event.nativeEvent.velocityX of react-native-gesture-handler/PanGestureHandler is always 0 velocityX of PanGestureHandler is always 0 Feb 21, 2025
@dprevost-LMI
Copy link
Author

The patch I used:

diff --git a/node_modules/react-native-pager-view/ios/Fabric/RNCPagerViewComponentView.mm b/node_modules/react-native-pager-view/ios/Fabric/RNCPagerViewComponentView.mm
index 8efd1ba..5d9b808 100644
--- a/node_modules/react-native-pager-view/ios/Fabric/RNCPagerViewComponentView.mm
+++ b/node_modules/react-native-pager-view/ios/Fabric/RNCPagerViewComponentView.mm
@@ -15,9 +15,7 @@
 
 using namespace facebook::react;
 
-@interface RNCPagerViewComponentView () <RCTRNCViewPagerViewProtocol, UIPageViewControllerDataSource, UIPageViewControllerDelegate, UIScrollViewDelegate, UIGestureRecognizerDelegate>
-
-@property(nonatomic, assign) UIPanGestureRecognizer* panGestureRecognizer;
+@interface RNCPagerViewComponentView () <RCTRNCViewPagerViewProtocol, UIPageViewControllerDataSource, UIPageViewControllerDelegate, UIScrollViewDelegate>
 
 @end
 
@@ -66,11 +64,6 @@ using namespace facebook::react;
         _destinationIndex = -1;
         _layoutDirection = @"ltr";
         _overdrag = NO;
-        UIPanGestureRecognizer* panGestureRecognizer = [UIPanGestureRecognizer new];
-        self.panGestureRecognizer = panGestureRecognizer;
-        panGestureRecognizer.delegate = self;
-        [self addGestureRecognizer: panGestureRecognizer];
-
     }
     
     return self;
@@ -405,30 +398,6 @@ using namespace facebook::react;
     return concreteComponentDescriptorProvider<RNCViewPagerComponentDescriptor>();
 }
 
-
-- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
-
-    // Recognize simultaneously only if the other gesture is RN Screen's pan gesture (one that is used to perform fullScreenGestureEnabled)
-    if (gestureRecognizer == self.panGestureRecognizer && [NSStringFromClass([otherGestureRecognizer class]) isEqual: @"RNSPanGestureRecognizer"]) {
-        UIPanGestureRecognizer* panGestureRecognizer = (UIPanGestureRecognizer*) gestureRecognizer;
-        CGPoint velocity = [panGestureRecognizer velocityInView:self];
-        BOOL isLTR = [self isLtrLayout];
-        BOOL isBackGesture = (isLTR && velocity.x > 0) || (!isLTR && velocity.x < 0);
-        
-        if (self.currentIndex == 0 && isBackGesture) {
-            scrollView.panGestureRecognizer.enabled = false;
-        } else {
-            const auto &viewProps = *std::static_pointer_cast<const RNCViewPagerProps>(_props);
-            scrollView.panGestureRecognizer.enabled = viewProps.scrollEnabled;
-        }
-        
-        return YES;
-    }
-    const auto &viewProps = *std::static_pointer_cast<const RNCViewPagerProps>(_props);
-    scrollView.panGestureRecognizer.enabled = viewProps.scrollEnabled;
-    return NO;
-}
-
 @end
 
 Class<RCTComponentViewProtocol> RNCViewPagerCls(void)
diff --git a/node_modules/react-native-pager-view/ios/ReactNativePageView.m b/node_modules/react-native-pager-view/ios/ReactNativePageView.m
index 998e70a..ab0fc7f 100644
--- a/node_modules/react-native-pager-view/ios/ReactNativePageView.m
+++ b/node_modules/react-native-pager-view/ios/ReactNativePageView.m
@@ -9,9 +9,7 @@
 #import "RCTOnPageSelected.h"
 #import <math.h>
 
-@interface ReactNativePageView () <UIPageViewControllerDataSource, UIPageViewControllerDelegate, UIScrollViewDelegate, UIGestureRecognizerDelegate>
-
-@property(nonatomic, assign) UIPanGestureRecognizer* panGestureRecognizer;
+@interface ReactNativePageView () <UIPageViewControllerDataSource, UIPageViewControllerDelegate, UIScrollViewDelegate>
 
 @property(nonatomic, strong) UIPageViewController *reactPageViewController;
 @property(nonatomic, strong) RCTEventDispatcher *eventDispatcher;
@@ -47,10 +45,6 @@
         _cachedControllers = [NSHashTable hashTableWithOptions:NSHashTableStrongMemory];
         _overdrag = NO;
         _layoutDirection = @"ltr";
-        UIPanGestureRecognizer* panGestureRecognizer = [UIPanGestureRecognizer new];
-        self.panGestureRecognizer = panGestureRecognizer;
-        panGestureRecognizer.delegate = self;
-        [self addGestureRecognizer: panGestureRecognizer];
     }
     return self;
 }
@@ -466,28 +460,6 @@
     return scrollDirection;
 }
 
-- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
-
-    // Recognize simultaneously only if the other gesture is RN Screen's pan gesture (one that is used to perform fullScreenGestureEnabled)
-    if (gestureRecognizer == self.panGestureRecognizer && [NSStringFromClass([otherGestureRecognizer class]) isEqual: @"RNSPanGestureRecognizer"]) {
-        UIPanGestureRecognizer* panGestureRecognizer = (UIPanGestureRecognizer*) gestureRecognizer;
-        CGPoint velocity = [panGestureRecognizer velocityInView:self];
-        BOOL isLTR = [self isLtrLayout];
-        BOOL isBackGesture = (isLTR && velocity.x > 0) || (!isLTR && velocity.x < 0);
-        
-        if (self.currentIndex == 0 && isBackGesture) {
-            self.scrollView.panGestureRecognizer.enabled = false;
-        } else {
-            self.scrollView.panGestureRecognizer.enabled = self.scrollEnabled;
-        }
-        
-        return YES;
-    }
-    
-    self.scrollView.panGestureRecognizer.enabled = self.scrollEnabled;
-    return NO;
-}
-
 - (BOOL)isLtrLayout {
     return [_layoutDirection isEqualToString:@"ltr"];
 }

@dprevost-LMI dprevost-LMI changed the title velocityX of PanGestureHandler is always 0 velocityX of PanGestureHandler is always 0 because of gestureRecognizer Feb 21, 2025
@dprevost-LMI dprevost-LMI changed the title velocityX of PanGestureHandler is always 0 because of gestureRecognizer velocityX of PanGestureHandler is always 0 because of gestureRecognizer on iOS Feb 21, 2025
@dprevost-LMI dprevost-LMI changed the title velocityX of PanGestureHandler is always 0 because of gestureRecognizer on iOS (iOS) velocityX of PanGestureHandler is always 0 because of gestureRecognizer Feb 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant