React-native-gesture-handler: Doesn't work in a modal

Created on 11 Apr 2018  ·  71Comments  ·  Source: software-mansion/react-native-gesture-handler

Hi !
I have a little issue on Android, onGestureEvent is not trigger when GestureHandler components is on a modal on Android. When I change the modal to a View, it works perfectly 👌

No problem on iOS

Android Bug Can repro Important

Most helpful comment

A little trick to solve it inside a modal:

import { TouchableWithoutFeedback } from 'react-native';
import { RectButton } from 'react-native-gesture-handler';
<TouchableWithoutFeedback onPress={...}
    <RectButton>
         ...
    </RectButton>
</TouchableWithoutFeedback>

All 71 comments

+1
any workaround?

I don’t use Modal for now, I just re-create it with a View in absolute position

using modal screen for now, after googling and chats Modal from RN considered too much buggy thing

+1

Hi, @martinezguillaume, @mordaha, @csto
I did take a look on this issue and I suppose it's not a matter of our library, but RN Core.

@osdnk is this fixable?

+1 gesture does not work on modal

I also ran into this bug today.

Same problem. Gesture does not work on modal on Android.
Expo for example

Same for me. Tested react-native's PanResponder handlers on modal - works fine.

I have a thoughts about this: when we are linking this library to android project, we are doing next step

@Override
            protected ReactRootView createRootView() {
                return new RNGestureHandlerEnabledRootView(MainActivity.this);
            }

And we know that modal is separate package. May be theres sense to do something same with it?

I was using a standard React Native Modal and was experiencing this issue.
I worked around the problem by creating a new screen and displaying it as a modal. I'm using react-native-navigation, so:

Navigation.showModal({
    component: {
      name: navRoutes.ImageModal,
      passProps: { image },
    },
  })

Gestures are working as expected on both iOS and Android, and I still get transparent background that I wanted from my original modal.

I have dug into it for a while.

  1. It's a problem of RNGH. Sorry 😒
  2. It happens bc modals are not rendered below an RN root view.
  3. It's fixable by replacing modals' mechanism in a similar way as we do with an RNRootView by wrapping it with some extra logic. See https://github.com/kmagiera/react-native-gesture-handler/blob/master/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootViewManager.java
  4. I have no time to do it now, it's time-consuming work and probably requires copying some code in an RNGH core on Android native side.

If someone wants and has time to do it, I'll happily review it and merge immediately if it would be workable and not too hacky.

@martinezguillaume @mordaha @csto @mars-lan @ParhamZare @ewendel @Via-profit @Dmitrylolo @LaVielle

Also, I've made a try two months ago.

https://github.com/kmagiera/react-native-gesture-handler/commit/139da18039683bed3c439c991c7eaf802086bf86

Maybe it could be an inspiration for someone 🤷‍♂️

Hey @osdnk I need this feature for my app, so I was thinking I could give it a try, but I don't have a lot of experience with RNGestureHandler, or with Android. Could you give me some more insight on what I would need to do to make it work ?
Also I was looking at your previous try, and I would like to know what's missing for it to be finished, and if it could be used as a starting point.

same error.

@kmagiera @osdnk any update on this?
even Touchable*'s don't work inside the modal and this is frustrating

+1. i use reanimated-bottom-sheet with modal

Any updates? Or perhaps, any other modal component that does not suffer from this issue? RN's modal honestly works like quite bad and is full of bugs (such as getting stuck if combined with an alert)

Odd. That component is supposed to use react's modal internally. Did it
make a difference to you?

El jue., 30 de mayo de 2019 14:38, Mars Lan notifications@github.com
escribió:

@cristianoccazinsp https://github.com/cristianoccazinsp I ended up
using https://github.com/react-native-community/react-native-modal


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/kmagiera/react-native-gesture-handler/issues/139?email_source=notifications&email_token=ALU263ACF3LNSRSPFWR45ELPYAGJTA5CNFSM4EZ6UZL2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODWS7SOQ#issuecomment-497416506,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ALU263GRH2KHBXUZBGHNKA3PYAGJTANCNFSM4EZ6UZLQ
.

@cristianoccazinsp It only uses RN's modal to cover the screen, which can be disabled by setting coverScreen to false

@cristianoccazinsp It only uses RN's modal to cover the screen, which can be disabled by setting coverScreen to false

But is there a way how to show fullscreen modal with this prop which is not rendered in root component of the app?

@jvaclavik I used it in conjunction with https://github.com/callstack/react-native-paper, which has a component called Portal designed specifically for this purpose.

This may not resolve all use cases but you can enable gestures in react native modal when setting the prop propagateSwipe to true.

This issue seems to be related to https://github.com/kmagiera/react-native-screens/issues/61

Don't use react native screens in android. Tested and working fine with 'reanimated-bottom-sheet'

if (Platform.OS === 'ios') {
useScreens();
}

This React Navigation Modal config for transparent bg is

ScreenOne: {
screen: ScreenOne,
navigationOptions: {
gesturesEnabled: false
},
}
{
mode: 'modal',
transparentCard: true,
headerMode: 'none',
cardStyle: {
backgroundColor: 'transparent',
opacity: 1
},
transitionConfig: () => ({
containerStyle: {
backgroundColor: 'transparent',
}
})
}

@osdnk fixed it?

This one is was so much pain.
I've spend some time before resolving to google it, pull my hairs out trying to figure out why on earth same component works on iOS and on android but only in some places inside application

we have the same issue - it doesn't work on modal.
i wonder if anyone is working on this or know of any status update ?
do we need to drop this library and switch to RN pan handlers ?
any suggestion ?

Same here. RectButton doesn't work inside https://github.com/react-native-community/react-native-modal

@deflorilemarului @kesha-antonov @fauker
Will spare you some time, neither Modal, nor Modal-based packages (if they don't require you to link native dependencies - they are based on react-native's Modal) will help you (I've tried all of them, basically).
All of gesture- related components (bottomsheet-behaviour for us) will not register any touches/swipes etc when rendered inside <Modal>...</Modal> on android;
There is 3 solutions I can think of:

  1. Use any other library if you are using modals. You may require rewrite some swipe-based components to PanResponder; this on is pain, but pretty straightforward;
  2. Use modals that are portals. They are not actually portals nor modals- portals are not supported by react-native because there is single application host - but they are working by placing Host Component somewhere up your application and renders Modal content in absolute view above app stack; this one is working solution, but you will loose any useContext() calls due to children being rendered above context providers; does not work for us, since navigation context is lost;
  3. Use modals provided by navigation library (react-navigation); this one works, but API is... not good - for one you could not make a single screen a modal, only a stack can be in modal mode; this one is solution I stick with.

Well, there is final solution - patch native android implementation (not possible if you are using expo) or wait for patch in a library and then wait until it merged into expo.

p.s.
Don't get me wrong, this library is amazing, and I cannot stress enough how much I appreciate work being poured into this and how much better the experience for end user, but bugs like this one make me want to pull my hairs out.

Few libraries requires us to deal with native context, if so:

For android, we will need a special care as stated in RNGH document:

Update your MainActivity.java file
Screen Shot 2019-11-30 at 12 17 07 PM

Hope it helps

Few libraries requires us to deal with native context, if so:

For android, we will need a special care as stated in RNGH document:

Update your MainActivity.java file
Screen Shot 2019-11-30 at 12 17 07 PM

Hope it helps

Yes, this worked perfectly for me. I almost got frustrated looking for solutions on making my android app swippable.

still not working
if change modal to view everything work just fine...

Hi @romanonthego ,

Well, there is final solution - patch native android implementation (not possible if you are using expo) or wait for patch in a library and then wait until it merged into expo.

Can you please tell me what to patch in side my native android code?

@osdnk That's exciting. Will it work with a DialogFragment as well?

After trying #937 I found out it didn't work for me...

Maybe it's because I'm using wix's react-native-navigation? As far as I know each and every screen is registered with the gestureHandlerRootHOC (the library works perfectly with normal, non modal views).

This is a fragment of the screen in which I tried the RectButton in a Modal (basically as it is in the doc update)

  renderSearchScreen = () => {
    const { showSearchHistory } = this.state;
    const ExampleWithHoc = gestureHandlerRootHOC(() => {
      return (
        <View style={genericStyles.container}>
          <SearchScreen
            searchBar={{
              ...this.searchBar,
              searchQuery: this.props.searchQuery,
            }}
            onBackPress={() => {
              this.setState({ showSearchHistory: false });
            }}
          />
        </View>
      );
    });

    if (showSearchHistory) {
      return (
        <RNModal
          animationType="fade"
          transparent
          visible={this.state.showSearchHistory}
          onRequestClose={() => {}}>
          <ExampleWithHoc />
        </RNModal>
      );
    }

    return null;
  };

The modal loads when it's supposed to, but the RectButton does not fire the onPress event. I tried making a minimum reproducible demo with a brand new app but then I ran into #848 #676 #835 (possible duplicates of one another).

whop #937

That's amazing! It still doesn't work with react-native-modal for me, though!

_// edit: Actually, default modal doesn't work either, but it should, starting from 1.6.0 if I am not mistaken? Will try to find out what's going wrong_

I've played around a bit and was able to find the issue. However, I am not sure what's causing it and how to fix it.

The problem in my case is, that I react-native-gesture-handler will not work inside a @react-navigation/stack, if placed inside a modal (so basically Stack.Navigator > SomeScreenComponent > Modal > gestureHandlerRootHOC(PanGestureHandler) fails).

If I cut the Stack Navigator out or use the Tab Navigator instead, it works like a charm, so I am pretty sure it's the Stack Navigators' fault.

Relevant package versions:

[email protected]
@react-navigation/[email protected]
@react-navigation/[email protected]

I'll try to setup a demo repo ASAP, let me know if I can provide any more helpful info.

Here is a demo app to (almost blank from npx react-native init), that will show the issue. You can toggle the stack navigator inside the app and see how the PanGestureHandler becomes functional and unfunctional.

https://github.com/mxmzb/react-native-breakable-app

I have a similar issue. It seems that the Stack.Navigator doesn't work well on Android. It doesn't matter if I use a mode="modal" or "card".

So i was playing around and had the following code

import { SafeAreaView, Button } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack'

import { enableScreens } from 'react-native-screens';
enableScreens(); // <-- this fucked it up

const Screen1 = ({ navigation }) => {
    return (
      <SafeAreaView style={{ flex: 1 }}>
        <Button title="Open Modal" onPress={() => navigation.push('Modal')} />
      </SafeAreaView>
    )
  }

  const Screen2 = ({ navigation }) => {
    return (
      <SafeAreaView style={{ flex: 1 }}>
        <Button title="Close Modal" onPress={() => navigation.goBack()} />
      </SafeAreaView>
    )
  }

const App = () => {

return (
        <NavigationContainer>
          <Stack.Navigator headerMode="none">
            <Stack.Screen name="Main" component={Screen1} />
            <Stack.Screen name="Modal" component={Screen2} />
          </Stack.Navigator>
        </NavigationContainer>
  )

}

Then I removed this line;
enableScreens();

And then it worked correctly on Android.

A little trick to solve it inside a modal:

import { TouchableWithoutFeedback } from 'react-native';
import { RectButton } from 'react-native-gesture-handler';
<TouchableWithoutFeedback onPress={...}
    <RectButton>
         ...
    </RectButton>
</TouchableWithoutFeedback>

I am having similar issue. Any work around ?

I was trying to use https://github.com/osdnk/react-native-reanimated-bottom-sheet inside a modal, and it's not possible, I finally solved with react-navigation screen animation:

https://github.com/osdnk/react-native-reanimated-bottom-sheet/issues/143#issuecomment-614300015

A little trick to solve it inside a modal:

import { TouchableWithoutFeedback } from 'react-native';
import { RectButton } from 'react-native-gesture-handler';
<TouchableWithoutFeedback onPress={...}
    <RectButton>
         ...
    </RectButton>
</TouchableWithoutFeedback>

Hey @gideaoms . I wonder how did your comment went unnoticed here. It definitely does the trick. Thanks man!

Here is a demo app to (almost blank from npx react-native init), that will show the issue. You can toggle the stack navigator inside the app and see how the PanGestureHandler becomes functional and unfunctional.

https://github.com/mxmzb/react-native-breakable-app

then, what is the solution?

I'm still having the same problem....
Any solution ou nothing yet ?

This is still a problem on 1.6.0

Tried every suggestions mentioned above but still no luck yet. Please help its really frustrating.
My react native version in 0.62.2 tried with both /react-native-gesture-handler 1.5.6 & 1.6.0.

still an issue on ^1.7.0

Is still not working :-1:

We use wix-navigation. Maybe something related?

Well, I found a possible workaround, it does exactly what we want and work for both iOS and Android.

https://www.youtube.com/watch?v=tLQjGHDiRkM

@steniowagner is that like a custom modal ? I wouldn't recommend it
just go with react-navigations or native-stack modal, it does work with it fine.

hmm, didn't test with react-navigations (sounded like too much for my case), but maybe it's the best way at the moment.

Thank you @a-eid !

According to the docs
https://docs.swmansion.com/react-native-gesture-handler/docs/#usage-with-modals-on-android

but still didn't work for me.

@gideaoms that tricks may works for button but my use case is to use PinchGestureHandler inside the modal.

A little trick to solve it inside a modal:

import { TouchableWithoutFeedback } from 'react-native';
import { RectButton } from 'react-native-gesture-handler';
<TouchableWithoutFeedback onPress={...}
    <RectButton>
         ...
    </RectButton>
</TouchableWithoutFeedback>

This issue is more than 2 years old, are there any plans to fix this?

I've created custom Slider components for my app and can't use them at all on Android, since a lot of views in my app are Modals

I've wrapped every screen and Modal component in a gestureHandlerRootHoC (using wix/react-native-navigation)

I've tried wrapping both the screen and the component with gestureHandlerRootHoc without success. I didn't try the RectButton approach because I need a PanGestureHandler in order to implement swipe-down-to-dismiss behaviour on the modal. It is frustrating because it works perfectly on iOS and, since I'm using react-native-modal, which actually comes with swipe-to-dismiss out-of-the-box, I've even tried using that approach instead and it works as long as you don't have scrollable content inside the modal because then it's buggy both on iOS and Android, so I'm kind of stuck...

To sum up:

  1. ❌ RNGH does not work in react-native's <Modal> component (even though the Component is wrapped in a gestureHandlerRootHOC)
  2. ✅ RNGH does work in a screen from wix/react-native-navigation's which is shown using Navigation.showModal (even though the Screen is wrapped in a gestureHandlerRootHOC)
  3. ✅ RNGH apparently does work if shown using react-navigation's push function with modal: true, but only when not using the native stack (enableScreens()/createNativeStackNavigator()).

I can provide more details if required.

react-native-modal-animated works with react-native-gesture-handler, because react-native-modal-animated creating a Modal just using a View.

@flyskywhy if react-native-modal-animated doesn't use a separate activity like react-native-modal then how it's render on top of everything? If it's using an absolute position then it could make a problem in some cases.

@waheedakhtar694 , it's using absolute. At least in my case, no problem :stuck_out_tongue_closed_eyes:

@jvaclavik I used it in conjunction with https://github.com/callstack/react-native-paper, which has a component called Portal designed specifically for this purpose.

Solved using Portal from react-native-paper as @jvaclavik said.
I wrapped my App with PaperProvider, then changed Modals to Views and wrapped them with gestureHandlerRootHOC and Portal.
Now bottom-sheet works on Android 😍

_EDIT: for some reason pan gestures are working but onPress events are not working (but ripple is shown)...
EDIT 2: that was a problem with the library I used, I fixed it changing touchable imports from "react-native" to "react-native-gesture-handler"_

Here's some code you can try

/*
 App.js:
 - import { Provider as PaperProvider } from "react-native-paper";
 - wrap your App with PaperProvider
*/

// ModalFixed.js
import { Portal } from 'react-native-paper';
import { gestureHandlerRootHOC } from 'react-native-gesture-handler';

const ModalFixed = (props) => {
  <View style={styles.modal}>
    <View style={styles.shadow} />
    {/* MODAL CONTENT HERE, you can put props.children to reuse this component */}
  </View>
}

const styles = StyleSheet.create({
  modal: {
    width: "100%",
    height: "100%"
  },
  shadow: {
    position: "absolute",
    width: "100%",
    height: "100%",
    backgroundColor: "rgba(0,0,0,0.3)",
  }
})

const _ModalFixed = gestureHandlerRootHOC(SheetPopup)
export default (props) => {
  return (
    <Portal>
      <_ModalFixed {...props} />
    </Portal>
  )
}

Its working for me:
<TouchableWithoutFeedback onPress={() => { console.log("press"); }} > <Text> <RectButton> ... </RectButton> </Text> </TouchableWithoutFeedback>

Any update on this? We have two projects where iOS is working as expected but Android modals are proving a headache. We'd rather not have to remove modals from the projects...that is a big design overhaul. :/

@DavidAPears have you tried wrapping you modals in gestureHandlerRootHOC ?

something like this ?


const ModalInner = gestureHandlerRootHOC(function GestureExample() {
  return (
    <View>
      { RNGH components . }
    </View>
  );
});

export default function ModalForX() {
  return (
    <Modal animationType="slide" transparent={false}>
      <ModalInner />
    </Modal>
  );
}


Combination of Portal from react-native-portalize and gestureHandlerRootHOC works for me. Something like that:

<Portal>
   <Modal>
      <GestureHandlerRootHOCWrappedComponent />
   </Modal>
</Portal>

setting coverSreen={false} on modal works. But need my modal cover the screen

import {Platform, Modal} from 'react-native';
import {gestureHandlerRootHOC} from 'react-native-gesture-handler';
import {AnimatedBottomSheet} from '../AnimatedBottomSheet';

const AnimatedBottomSheetWrapper = Platform.OS === 'android' ? gestureHandlerRootHOC(AnimatedBottomSheet) : AnimatedBottomSheet;

Not sure if this is going to help someone, i also had issues using this library with react-native-modal, but beside wrapping children of modal gestureHandlerRootHOC (this is working fine for buttons, but i had issues having text input in modal + avoidKeyboard = true and on every press of key, keyboard was closing ) So only thing i did, is made modal children wrapper, something like this:

import Modal from 'react-native-modal';
import { gestureHandlerRootHOC } from 'react-native-gesture-handler';

const GestureHandlerWrapper = gestureHandlerRootHOC(
  ({ children }) => <View>{children}</View>,
  { flex: 0 }
);

export const CustomModal: React.FC<Props> = ({
  children,
...rest
}) => {
  return (
    <Modal
      {...rest}
    >
      <GestureHandlerWrapper>    
          {children} 
      </GestureHandlerWrapper>
    </Modal>
  );
};
Was this page helpful?
0 / 5 - 0 ratings