diff --git a/android/src/main/java/com/swmansion/gesturehandler/core/NativeViewGestureHandler.kt b/android/src/main/java/com/swmansion/gesturehandler/core/NativeViewGestureHandler.kt index c588eb47fe..36e5dbacbc 100644 --- a/android/src/main/java/com/swmansion/gesturehandler/core/NativeViewGestureHandler.kt +++ b/android/src/main/java/com/swmansion/gesturehandler/core/NativeViewGestureHandler.kt @@ -10,6 +10,7 @@ import com.facebook.react.views.scroll.ReactScrollView import com.facebook.react.views.swiperefresh.ReactSwipeRefreshLayout import com.facebook.react.views.text.ReactTextView import com.facebook.react.views.textinput.ReactEditText +import com.facebook.react.views.view.ReactViewGroup import com.swmansion.gesturehandler.react.RNGestureHandlerButtonViewManager import com.swmansion.gesturehandler.react.isScreenReaderOn @@ -85,6 +86,7 @@ class NativeViewGestureHandler : GestureHandler() { is ReactSwipeRefreshLayout -> this.hook = SwipeRefreshLayoutHook(this, view) is ReactScrollView -> this.hook = ScrollViewHook() is ReactTextView -> this.hook = TextViewHook() + is ReactViewGroup -> this.hook = ReactViewGroupHook() } } @@ -105,7 +107,7 @@ class NativeViewGestureHandler : GestureHandler() { if (state == STATE_UNDETERMINED && !hook.canBegin(event)) { cancel() } else { - view.onTouchEvent(event) + hook.sendTouchEvent(view, event) if ((state == STATE_UNDETERMINED || state == STATE_BEGAN) && hook.canActivate(view)) { activate() @@ -123,12 +125,12 @@ class NativeViewGestureHandler : GestureHandler() { when { shouldActivateOnStart -> { tryIntercept(view, event) - view.onTouchEvent(event) + hook.sendTouchEvent(view, event) activate() } tryIntercept(view, event) -> { - view.onTouchEvent(event) + hook.sendTouchEvent(view, event) activate() } @@ -143,7 +145,7 @@ class NativeViewGestureHandler : GestureHandler() { } } } else if (state == STATE_ACTIVE) { - view.onTouchEvent(event) + hook.sendTouchEvent(view, event) } } @@ -152,7 +154,7 @@ class NativeViewGestureHandler : GestureHandler() { val event = MotionEvent.obtain(time, time, MotionEvent.ACTION_CANCEL, 0f, 0f, 0).apply { action = MotionEvent.ACTION_CANCEL } - view!!.onTouchEvent(event) + hook.sendTouchEvent(view, event) event.recycle() } @@ -211,6 +213,11 @@ class NativeViewGestureHandler : GestureHandler() { * by this one. */ fun shouldCancelRootViewGestureHandlerIfNecessary() = false + + /** + * Passes the event down to the underlying view using the correct method. + */ + fun sendTouchEvent(view: View?, event: MotionEvent) = view?.onTouchEvent(event) } private class TextViewHook() : NativeViewGestureHandlerHook { @@ -298,4 +305,12 @@ class NativeViewGestureHandler : GestureHandler() { private class ScrollViewHook : NativeViewGestureHandlerHook { override fun shouldCancelRootViewGestureHandlerIfNecessary() = true } + + private class ReactViewGroupHook : NativeViewGestureHandlerHook { + // There are cases where a native component is wrapped with a `ReactViewGroup` (the component is rendered + // inside a `` component in JS). In such cases, calling `onTouchEvent` wouldn't work as those are + // ignored by the wrapper view. Instead `dispatchTouchEvent` can be used, which causes the view to dispatch + // the event to its children. + override fun sendTouchEvent(view: View?, event: MotionEvent) = view?.dispatchTouchEvent(event) + } }