Skip to content

Instantly share code, notes, and snippets.

@zeh
Last active July 6, 2020 14:21
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zeh/346ec64d45be7cf4e3bbed734fd80d31 to your computer and use it in GitHub Desktop.
Save zeh/346ec64d45be7cf4e3bbed734fd80d31 to your computer and use it in GitHub Desktop.

Idea

#127 "ScrollView in modal prevents modal from dismissing sometimes" - https://github.com/react-navigation/stack/issues/127

This issue has a good discussion and a comment:

brentvatne: it's not really possible for react-navigation to guess when you may or may not want to close the modal depending on other gestures you have inside of a scene, you need to define that behavior for yourself. you can access the gesture context like this: https://github.com/react-navigation/react-navigation-stack/blob/5f157cbc16f2dd15363304ab3c78663b0ed36de0/example/src/GestureInteraction.js#L55-L56 then you can use react-native-gesture-handler tools to make this behave how you like.

And:

ryan-gilb (Dec 29): Hey @skhavari! If you still need help with this, check out this snack: https://snack.expo.io/@rgilbert/scrollable-modal-with-dismissal

This seems to be a pretty clean version.

#315 "Document how to build a modal that dismisses by gesture only when ScrollView is at top" - react-navigation/react-navigation.github.io#315

This was based on issue #127. @ryan-gilb created a snack Dec 29 2018: https://snack.expo.io/@rgilbert/full-screen-modal-v3

This seems like the same version as above, but more raw. A temporary version? Anyhow, it exhibits the drag miss issue.

#333 "Document modal that dismisses by gesture only when ScrollView is at top" - react-navigation/react-navigation.github.io#333

Based on the additional issue, he created an example in Dec 29 2018: https://github.com/react-navigation/react-navigation.github.io/pull/333/files

Basically:

<StackGestureContext.Consumer>
{ref => (
  <ScrollView
    waitFor={this.state.scrolledTop ? ref : undefined}
    onScroll={({ nativeEvent }) => {
      const scrolledTop = nativeEvent.contentOffset.y <= 0;
      this.setState({ scrolledTop });
    }}
    scrollEventThrottle={16}>
    <Text>{content}</Text>
  </ScrollView>
)}
</StackGestureContext.Consumer>

But it has an issue: it doesn't always work. Sometimes, pulling from the top uses the scroll view.

@brentvatne also had additional reservations:

Thanks for this! Love the writing style.

The file he's referring to is this:

https://github.com/react-navigation/stack/blob/7d13e7b7130b91a5dd3c5c8ee76ece15d137cc30/example/src/TransparentStack.js

Which got moved to this:

https://github.com/react-navigation/stack/blob/master/example/src/TransparentStack.tsx

But there's really not much there other than a different transition config.

defaultNavigationOptions: {
  gestureEnabled: false,
  cardTransparent: true,
  cardStyleInterpolator: ({ current: { progress } }) => {
    const opacity = Animated.interpolate(progress, {
      inputRange: [0, 0.5, 0.9, 1],
      outputRange: [0, 0.25, 0.7, 1],
    });

    return {
      cardStyle: {
        opacity,
      },
    };
  },
},

Issue

Gesture works, but only sometimes.

Issues that report the same:

#166 ScrollViews conflict with the swipe back gesture on iOS - https://github.com/react-navigation/stack/issues/166

No solution.

Points to the (older) issue: https://github.com/react-navigation/stack/issues/137 that might be related to diagonal swiping?

For him, this seems to work:

With the limited time I had to look in to this I would guess that the pickiness has to do with the rather low maxDeltaY set in src/views/StackView/StackViewLayout.tsx -> gestureActivationCriteria() but I didn't have the time to try and change it. If someone has the time to try fiddling with this so we can get less annoyed when failing to swipe back in RN apps that would awesome!

Other ideas/proposals

An example from React-navigation-stack, using StackGestureContext. Uses a if (!this.state.interactionComplete) that was worth investigating:

InteractionManager.runAfterInteractions(() => {
    this.setState({ interactionComplete: true });
});

But turns out this is useless to us. It only runs at the end of screen transitions (has nothing to do with gesture interactions, for example).

Different implementation for waitFor

And #166 Also proposes a different implementation for waitFor:

<NativeViewGestureHandler waitFor={ref}>
    <ScrollView>...</ScrollView>
</NativeViewGestureHandler>

Or as in here:

<NativeViewGestureHandler waitFor={ref}>
    <MapView style={{ flex: 1 }} />
</NativeViewGestureHandler>

But this has the same issues as a ReactNavigation.ScrollView with waitFor.

@thomas-dm
Copy link

Thanks for the comprehensive list of issues and tests related to nested in modals! 👍
Did you ever end up finding an elegant solution to this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment