software-mansion / react-native-gesture-handler

Declarative API exposing platform native touch and gesture system to React Native.
https://docs.swmansion.com/react-native-gesture-handler/
MIT License
6.12k stars 979 forks source link

`GestureHandler` not detecting gestures in nested children #2328

Closed KrisLau closed 1 year ago

KrisLau commented 1 year ago

Description

I'm trying to check the pan velocity to decide when to collapse the header (the header collapse state is managed by a state). I managed to use the GestureHandler to detect a pan gesture but it looks like it's not detecting the gesture if it's the children of a ScrollView. It's not really just a scroll view as some tabs have just a scroll view and some have the wix calendar component or a webview.

The red box is the part where the gestures are not being detected and the green is where it is being detected: image

Is there a way to force the GestureHandler to detect the gestures in the nested children?

(snack doesn't log the event but works in my personal project i attached it anyway as a code example)

Steps to reproduce

  1. Add a GestureHandler with a pan gesture as the gesture
  2. Inside, add a TabView which has a ScrollView within each tab.

Snack or a link to a repository

https://snack.expo.dev/@kris_lau/gesturehandler

Gesture Handler version

2.8.0

React Native version

0.70.6

Platforms

Android, iOS

JavaScript runtime

Hermes

Workflow

Expo bare workflow

Architecture

Paper (Old Architecture)

Build type

Debug mode

Device

iOS simulator

Device model

iPhone 11 (13.6)

Acknowledgements

Yes

rizwan92 commented 1 year ago

@KrisLau i think i am also facing the same issue can you help me if you find any solution

2332

j-piasecki commented 1 year ago

You need to wrap your ScrollViews with another GestureDetector recognizing Native gesture. It's role is to allow Gesture Handler to work alongside the touch handling of native components. Other than that, you will also need to mark the pan gesture and the newly created native gesture as simultaneous. Here's how it can look:

    const renderScene = ({route: tabRoute}) => {
    const scrollGesture = Gesture.Native().simultaneousWithExternalGesture(panGesture);

    switch (tabRoute.key) {
      case 'Schedule':
        return (
          <GestureDetector gesture={scrollGesture}>
            <ScrollView>
              <Text>text</Text>
              <Text>text</Text>
              <Text>text</Text>
              <Text>text</Text>
              <Text>text</Text>
            </ScrollView>
          </GestureDetector>
        );
      case 'Roster':
        return (
          <GestureDetector gesture={scrollGesture}>
            <ScrollView>
              <Text>text</Text>
              <Text>text</Text>
              <Text>text</Text>
              <Text>text</Text>
              <Text>text</Text>
            </ScrollView>
          </GestureDetector>
        );
      case 'News':
        return (
          <GestureDetector gesture={scrollGesture}>
            <ScrollView>
              <Text>text</Text>
              <Text>text</Text>
              <Text>text</Text>
              <Text>text</Text>
              <Text>text</Text>
            </ScrollView>
          </GestureDetector>
        );
      case 'Store':
        return (
          <GestureDetector gesture={scrollGesture}>
            <ScrollView>
              <Text>text</Text>
              <Text>text</Text>
              <Text>text</Text>
              <Text>text</Text>
              <Text>text</Text>
            </ScrollView>
          </GestureDetector>
        );
      case 'Live':
        return (
          <GestureDetector gesture={scrollGesture}>
            <ScrollView>
              <Text>text</Text>
              <Text>text</Text>
              <Text>text</Text>
              <Text>text</Text>
              <Text>text</Text>
            </ScrollView>
          </GestureDetector>
        );
    }
  };

In this case, I'm using the same native gesture for every page which should be safe as only one is rendered at a time, however, depending on your specific use-case it may be necessary to make a separate native gesture for every scroll view.

Also, if you want it to work on Android, you need to wrap your app with GestureHandlerRootView.