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 ; +}