Skip to content
Open
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
Expand Up @@ -161,6 +161,9 @@ class NativeViewGestureHandler : GestureHandler() {
cancel()
} else {
hook.sendTouchEvent(view, event)
if (shouldStopNestedScroll()) {
view.stopNestedScroll()
}

if ((state == STATE_UNDETERMINED || state == STATE_BEGAN) && hook.canActivate(view)) {
activate()
Expand Down Expand Up @@ -206,9 +209,19 @@ class NativeViewGestureHandler : GestureHandler() {
action = MotionEvent.ACTION_CANCEL
}
hook.sendTouchEvent(view, event)
if (shouldStopNestedScroll()) {
view?.stopNestedScroll()
}
event.recycle()
}

// Once the handler is active, it delivers touches straight to the view's `onTouchEvent`. Normally
// touches arrive through `View.dispatchTouchEvent`, which also ends the nested scroll when the finger
// goes up. Because we skip it, the nested scroll stays open and the parent never finds out that the
// gesture is over - e.g. SwipeRefreshLayout never fires refresh (#4485). While the handler is not
// active, the view still receives touches the regular way, so Android takes care of it.
private fun shouldStopNestedScroll() = state == STATE_ACTIVE && hook.shouldStopNestedScroll()

override fun onCancel() = dispatchCancelEventToView()

override fun onFail() = dispatchCancelEventToView()
Expand Down Expand Up @@ -348,6 +361,12 @@ class NativeViewGestureHandler : GestureHandler() {
*/
fun canBegin(event: MotionEvent) = true

/**
* Whether the view's nested scroll should be stopped when the active gesture ends. Touches
* are fed through `onTouchEvent`, so `View.dispatchTouchEvent` never gets to do it.
*/
fun shouldStopNestedScroll() = false

/**
* Checks whether handler can activate. Used by TextViewHook.
*/
Expand Down Expand Up @@ -523,6 +542,10 @@ class NativeViewGestureHandler : GestureHandler() {

private class ScrollViewHook : NativeViewGestureHandlerHook {
override fun shouldCancelRootViewGestureHandlerIfNecessary() = true

// ScrollView starts a nested scroll on DOWN but never stops it itself. Without this the
// parent's `onStopNestedScroll` never runs, e.g. SwipeRefreshLayout never triggers refresh.
override fun shouldStopNestedScroll() = true
}

private class ReactViewGroupHook : NativeViewGestureHandlerHook {
Expand Down
Loading