Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import android.content.Context;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import com.facebook.react.ReactRootView;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
Expand Down Expand Up @@ -555,7 +556,7 @@ public void onCatalystInstanceDestroy() {
while (!mRoots.isEmpty()) {
int sizeBefore = mRoots.size();
RNGestureHandlerRootHelper root = mRoots.get(0);
ReactRootView reactRootView = root.getRootView();
ViewGroup reactRootView = root.getRootView();
if (reactRootView instanceof RNGestureHandlerEnabledRootView) {
((RNGestureHandlerEnabledRootView) reactRootView).tearDown();
} else {
Expand All @@ -579,7 +580,8 @@ private void tryInitializeHandlerForReactRootView(int ancestorViewTag) {
synchronized (mRoots) {
for (int i = 0; i < mRoots.size(); i++) {
RNGestureHandlerRootHelper root = mRoots.get(i);
if (root.getRootView().getRootViewTag() == rootViewTag) {
ViewGroup rootView = root.getRootView();
if (rootView instanceof ReactRootView && ((ReactRootView) rootView).getRootViewTag() == rootViewTag) {
// we have found root helper registered for a given react root, we don't need to
// initialize a new one then
return;
Expand Down Expand Up @@ -638,7 +640,8 @@ public void unregisterRootHelper(RNGestureHandlerRootHelper root) {
synchronized (mRoots) {
for (int i = 0; i < mRoots.size(); i++) {
RNGestureHandlerRootHelper root = mRoots.get(i);
if (root.getRootView().getRootViewTag() == rootViewTag) {
ViewGroup rootView = root.getRootView();
if (rootView instanceof ReactRootView && ((ReactRootView) rootView).getRootViewTag() == rootViewTag) {
return root;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
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.swmansion.gesturehandler.GestureHandler;
import com.swmansion.gesturehandler.GestureHandlerOrchestrator;

Expand All @@ -20,22 +21,22 @@ public class RNGestureHandlerRootHelper {
private final ReactContext mContext;
private final GestureHandlerOrchestrator mOrchestrator;
private final GestureHandler mJSGestureHandler;
private final ReactRootView mReactRootView;
private final ViewGroup mReactRootView;

private boolean mShouldIntercept = false;
private boolean mPassingTouch = false;

private static ReactRootView findRootViewTag(ViewGroup viewGroup) {
private static ViewGroup findRootViewTag(ViewGroup viewGroup) {
UiThreadUtil.assertOnUiThread();
ViewParent parent = viewGroup;
while (parent != null && !(parent instanceof ReactRootView)) {
while (parent != null && !(parent instanceof ReactRootView || RNGHModalUtils.isDialogRootViewGroup(parent))) {
parent = parent.getParent();
}
if (parent == null) {
throw new IllegalStateException("View " + viewGroup + " has not been mounted under" +
" ReactRootView");
}
return (ReactRootView) parent;
return (ViewGroup) parent;
}

public RNGestureHandlerRootHelper(ReactContext context, ViewGroup wrappedView) {
Expand Down Expand Up @@ -76,7 +77,7 @@ public void tearDown() {
module.unregisterRootHelper(this);
}

public ReactRootView getRootView() {
public ViewGroup getRootView() {
return mReactRootView;
}

Expand All @@ -99,7 +100,11 @@ protected void onCancel() {
long time = SystemClock.uptimeMillis();
MotionEvent event = MotionEvent.obtain(time, time, MotionEvent.ACTION_CANCEL, 0, 0, 0);
event.setAction(MotionEvent.ACTION_CANCEL);
mReactRootView.onChildStartedNativeGesture(event);
if (mReactRootView instanceof ReactRootView) {
((ReactRootView) mReactRootView).onChildStartedNativeGesture(event);
} else {
RNGHModalUtils.dialogRootViewGroupOnChildStartedNativeGesture(mReactRootView, event);
}
}
}

Expand Down
25 changes: 25 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,31 @@ You can check out [this example project](https://github.com/henrikra/nativeNavig

Remember that you need to wrap each screen that you use in your app with `gestureHandlerRootHOC` as with native navigation libraries each screen maps to a separate root view. It will not be enough to wrap the main screen only.

### Usage with modals on Android
On Android RNGH does not work by default because modals are not located under React Native Root view in native hierarchy.
In order to make it workable, components need to be wrapped with `gestureHandlerRootHOC` (it's no-op on iOS and web).

E.g.
```js
const ExampleWithHoc = gestureHandlerRootHOC(
function GestureExample() {
return (
<View>
<DraggableBox />
</View>
);
}
);

export default function Example() {
return (
<Modal animationType="slide" transparent={false}>
<ExampleWithHoc />
</Modal>
);
}
```

Comment on lines +160 to +184

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a question, would it be possible to export a modal from RNGH that already handles gestures as it should on Android?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... but let's do it in follow-up

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I try to use example, but it does not work :(

### For library authors

If you're using gesture handler in your component library, you may want to wrap your library's code in the `GestureHandlerRootView` component. This will avoid extra configuration in `MainActivity.java` for the user.
Expand Down