diff --git a/android/src/main/java/com/facebook/react/views/modal/RNGHModalUtils.java b/android/src/main/java/com/facebook/react/views/modal/RNGHModalUtils.java
deleted file mode 100644
index b7e9858163..0000000000
--- a/android/src/main/java/com/facebook/react/views/modal/RNGHModalUtils.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.facebook.react.views.modal;
-
-import android.view.MotionEvent;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-
-/**
- * For handling gestures inside RNGH we need to have access to some methods of
- * `ReactModalHostView.DialogRootViewGroup`. This class is not available outside
- * package so this file exports important features.
- */
-
-public class RNGHModalUtils {
- public static void dialogRootViewGroupOnChildStartedNativeGesture(ViewGroup modal, MotionEvent androidEvent) {
- ((ReactModalHostView.DialogRootViewGroup) modal).onChildStartedNativeGesture(androidEvent);
- }
-
- public static boolean isDialogRootViewGroup(ViewParent modal) {
- return modal instanceof ReactModalHostView.DialogRootViewGroup;
- }
-}
diff --git a/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt b/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt
index f2981386ec..8c2045331f 100644
--- a/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt
+++ b/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt
@@ -5,11 +5,11 @@ import android.util.Log
import android.view.MotionEvent
import android.view.ViewGroup
import android.view.ViewParent
-import com.facebook.react.ReactRootView
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.UiThreadUtil
import com.facebook.react.common.ReactConstants
-import com.facebook.react.views.modal.RNGHModalUtils
+import com.facebook.react.uimanager.RootView
+import com.facebook.react.views.modal.ReactModalHostView
import com.swmansion.gesturehandler.GestureHandler
import com.swmansion.gesturehandler.GestureHandlerOrchestrator
@@ -71,10 +71,8 @@ class RNGestureHandlerRootHelper(private val context: ReactContext, wrappedView:
val event = MotionEvent.obtain(time, time, MotionEvent.ACTION_CANCEL, 0f, 0f, 0).apply {
action = MotionEvent.ACTION_CANCEL
}
- if (rootView is ReactRootView) {
+ if (rootView is RootView) {
rootView.onChildStartedNativeGesture(event)
- } else {
- RNGHModalUtils.dialogRootViewGroupOnChildStartedNativeGesture(rootView, event)
}
}
}
@@ -122,7 +120,7 @@ class RNGestureHandlerRootHelper(private val context: ReactContext, wrappedView:
private fun findRootViewTag(viewGroup: ViewGroup): ViewGroup {
UiThreadUtil.assertOnUiThread()
var parent: ViewParent? = viewGroup
- while (parent != null && parent !is ReactRootView && !RNGHModalUtils.isDialogRootViewGroup(parent)) {
+ while (parent != null && parent !is RootView) {
parent = parent.parent
}
checkNotNull(parent) {
diff --git a/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt b/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt
index f66c883dad..b6f3dbb467 100644
--- a/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt
+++ b/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt
@@ -4,9 +4,12 @@ import android.content.Context
import android.util.Log
import android.view.MotionEvent
import android.view.ViewGroup
+import android.view.ViewParent
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.UiThreadUtil
import com.facebook.react.common.ReactConstants
+import com.facebook.react.uimanager.RootView
+import com.facebook.react.views.modal.ReactModalHostView
import com.facebook.react.views.view.ReactViewGroup
class RNGestureHandlerRootView(context: Context?) : ReactViewGroup(context) {
@@ -51,6 +54,12 @@ class RNGestureHandlerRootView(context: Context?) : ReactViewGroup(context) {
if (parent is RNGestureHandlerEnabledRootView || parent is RNGestureHandlerRootView) {
return true
}
+ // Checks other roots views but it's mainly for ReactModalHostView.DialogRootViewGroup
+ // since modals are outside RN hierachy and we have to initialize GH's root view for it
+ // Note that RNGestureHandlerEnabledRootView implements RootView - that's why this check has to be below
+ if (parent is RootView) {
+ return false
+ }
parent = parent.parent
}
return false
diff --git a/example/android/app/src/main/java/com/example/MainActivity.java b/example/android/app/src/main/java/com/example/MainActivity.java
index 7af3d4880e..557797a890 100644
--- a/example/android/app/src/main/java/com/example/MainActivity.java
+++ b/example/android/app/src/main/java/com/example/MainActivity.java
@@ -1,9 +1,6 @@
package com.example;
import com.facebook.react.ReactActivity;
-import com.facebook.react.ReactActivityDelegate;
-import com.facebook.react.ReactRootView;
-import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
public class MainActivity extends ReactActivity {
@@ -15,14 +12,4 @@ public class MainActivity extends ReactActivity {
protected String getMainComponentName() {
return "Example";
}
-
- @Override
- protected ReactActivityDelegate createReactActivityDelegate() {
- return new ReactActivityDelegate(this, getMainComponentName()) {
- @Override
- protected ReactRootView createRootView() {
- return new RNGestureHandlerEnabledRootView(MainActivity.this);
- }
- };
- }
}
diff --git a/example/src/App.tsx b/example/src/App.tsx
index de987cd8c2..0efb6aebaf 100644
--- a/example/src/App.tsx
+++ b/example/src/App.tsx
@@ -14,6 +14,7 @@ import DoubleDraggable from './release_tests/doubleDraggable';
import { ComboWithGHScroll } from './release_tests/combo';
import { TouchablesIndex, TouchableExample } from './release_tests/touchables';
import Rows from './release_tests/rows';
+import NestedGestureHandlerRootViewWithModal from './release_tests/nestedGHRootViewWithModal';
import { PinchableBox } from './recipes/scaleAndRotate';
import PanAndScroll from './recipes/panAndScroll';
import { BottomSheet } from './showcase/bottomSheet';
@@ -67,6 +68,10 @@ const EXAMPLES: ExamplesSection[] = [
{
sectionTitle: 'Release tests',
data: [
+ {
+ name: 'Modals with nested GHRootViews - issue #139',
+ component: NestedGestureHandlerRootViewWithModal,
+ },
{ name: 'Double pinch & rotate', component: DoublePinchRotate },
{ name: 'Double draggable', component: DoubleDraggable },
{ name: 'Rows', component: Rows },
diff --git a/example/src/release_tests/nestedGHRootViewWithModal.tsx b/example/src/release_tests/nestedGHRootViewWithModal.tsx
new file mode 100644
index 0000000000..17cf26dde1
--- /dev/null
+++ b/example/src/release_tests/nestedGHRootViewWithModal.tsx
@@ -0,0 +1,63 @@
+import * as React from 'react';
+import { useState } from 'react';
+import { StyleSheet, Modal, View, Text } from 'react-native';
+
+import {
+ GestureHandlerRootView,
+ TouchableOpacity,
+} from 'react-native-gesture-handler';
+import { DraggableBox } from '../basic/draggable';
+
+export default function App() {
+ const [isModalVisible, setIsModalVisible] = useState(false);
+
+ function ToggleModalButton() {
+ return (
+ setIsModalVisible((visible) => !visible)}>
+ {isModalVisible ? 'Close' : 'Open'} modal
+
+ );
+ }
+
+ return (
+
+
+ DraggableBox inside modal should be moveable
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+const styles = StyleSheet.create({
+ modalView: {
+ margin: 20,
+ marginTop: 200,
+ backgroundColor: 'transparent',
+ borderRadius: 6,
+ padding: 20,
+ alignItems: 'center',
+ borderWidth: 2,
+ },
+ container: {
+ flex: 1,
+ display: 'flex',
+ alignItems: 'center',
+ },
+ description: {
+ margin: 20,
+ },
+ button: {
+ borderWidth: 2,
+ padding: 10,
+ },
+});
diff --git a/src/GestureHandlerRootView.android.tsx b/src/GestureHandlerRootView.android.tsx
index 706f01eb7d..459565ee2d 100644
--- a/src/GestureHandlerRootView.android.tsx
+++ b/src/GestureHandlerRootView.android.tsx
@@ -1,34 +1,18 @@
import * as React from 'react';
-import { PropsWithChildren } from 'react';
-import { View, requireNativeComponent } from 'react-native';
+import { requireNativeComponent } from 'react-native';
+import { GestureHandlerRootViewProps } from './GestureHandlerRootView';
const GestureHandlerRootViewNative = requireNativeComponent(
'GestureHandlerRootView'
);
-const GestureHandlerRootViewContext = React.createContext(false);
-
-type Props = PropsWithChildren>;
-
-export default function GestureHandlerRootView({ children, ...rest }: Props) {
+export default function GestureHandlerRootView({
+ children,
+ ...rest
+}: GestureHandlerRootViewProps) {
return (
-
- {(available) => {
- if (available) {
- // If we already have a parent wrapped in the gesture handler root view,
- // We don't need to wrap it again in root view
- // We still wrap it in a normal view so our styling stays the same
- return {children};
- }
-
- return (
-
-
- {children}
-
-
- );
- }}
-
+
+ {children}
+
);
}
diff --git a/src/GestureHandlerRootView.tsx b/src/GestureHandlerRootView.tsx
index f20f2993ac..610c771be3 100644
--- a/src/GestureHandlerRootView.tsx
+++ b/src/GestureHandlerRootView.tsx
@@ -1,3 +1,12 @@
-import { View } from 'react-native';
+import * as React from 'react';
+import { PropsWithChildren } from 'react';
+import { View, ViewProps } from 'react-native';
-export default View;
+export interface GestureHandlerRootViewProps
+ extends PropsWithChildren {}
+
+export default function GestureHandlerRootView({
+ ...rest
+}: GestureHandlerRootViewProps) {
+ return ;
+}