react-native
react-native copied to clipboard
In Android touchMove is cancelled when intercepted by native gesture from child
Description
Hey! I'm not sure if you can call this a bug, but I might be missing some of the functionality in touch event handling. Currently, on Android touchMove
event seems to be cancelled when native gesture is recognized and intercepted in child component. While going through your source code, I have noticed that it is done intentionally in JSTouchDispatcher.java
:
public void onChildStartedNativeGesture(
MotionEvent androidEvent, EventDispatcher eventDispatcher) {
if (mChildIsHandlingNativeGesture) {
// This means we previously had another child start handling this native gesture and now a
// different native parent of that child has decided to intercept the touch stream and handle
// the gesture itself. Example where this can happen: HorizontalScrollView in a ScrollView.
return;
}
dispatchCancelEvent(androidEvent, eventDispatcher);
mChildIsHandlingNativeGesture = true;
mTargetTag = -1;
}
I would still like to receive touchMove and specifically touchEnd events when the gesture starts and ends. However, now I would only get a few touchMove events and touchCancelled. It doesn't seem to be difficult to implement, but maybe there is a reason why this approach is chosen?
Steps to reproduce
- Initialize the app simply
npx react-native@latest init AwesomeProject22
- Add a simple onTouchMove to the top view
onTouchMove={()=>console.log("moving")}
- Run the app with
npx react-native run-android
- Try to trigger touch move event. When moving to the sides, everything seems okay. When you start dragging to the top or bottom, only a few touchMove events are triggered and then cancelled until the next touchStart event.
React Native Version
0.74.1
Affected Platforms
Runtime - Android
Output of npx react-native info
info Fetching system and libraries information...
(node:2310) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
System:
OS: macOS 14.4.1
CPU: (12) arm64 Apple M2 Pro
Memory: 118.08 MB / 16.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 22.1.0
path: ~/.nvm/versions/node/v22.1.0/bin/node
Yarn:
version: 3.6.4
path: /opt/homebrew/bin/yarn
npm:
version: 10.3.0
path: ~/.nvm/versions/node/v22.1.0/bin/npm
Watchman:
version: 2024.04.29.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.14.3
path: /Users/andrius.zaleckis/.rvm/gems/ruby-3.2.2/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 23.4
- iOS 17.4
- macOS 14.4
- tvOS 17.4
- visionOS 1.1
- watchOS 10.4
Android SDK:
API Levels:
- "34"
Build Tools:
- 34.0.0
- 35.0.0
System Images:
- android-34 | Google APIs ARM 64 v8a
- android-34 | Google Play ARM 64 v8a
Android NDK: Not Found
IDEs:
Android Studio: 2023.3 AI-233.14808.21.2331.11709847
Xcode:
version: 15.3/15E204a
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.11
path: /opt/homebrew/opt/openjdk@17/bin/javac
Ruby:
version: 3.2.2
path: /Users/andrius.zaleckis/.rvm/rubies/ruby-3.2.2/bin/ruby
npmPackages:
"@react-native-community/cli": Not Found
react:
installed: 18.2.0
wanted: 18.2.0
react-native:
installed: 0.74.1
wanted: 0.74.1
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: false
iOS:
hermesEnabled: true
newArchEnabled: false
Stacktrace or Logs
No crashes or failures recorded.
Reproducer
The issue does not require a reproducer.
Screenshots and Videos
No response
I don't think a reproducer is necessary in this example, but I can create it on further request.
I don't think a reproducer is necessary in this example, but I can create it on further request.
Please do. It will save us time when we get to investigating this issue
Have added a reproducer: https://github.com/AndriusZal/44594-Reproducer
Within the Metro you will notice that when you touch move, the log will print a message with a counter. This counter resets when touch ends. The issue occurs when dragging is recognized by native recognizer within scroll view and touch move event is replaced with dragging event and scroll is happening. Then the touch is cancelled and we are not getting the touch end event. We can trigger touch cancelled event, but I still need to see all touch move events which are happening during drag.
I don't mind to providing the fix myself, I just might need some backstory why this approach is chosen.
My comment maybe unrelated to the above issue but I have a doubt regarding the usage of onChildStartedNativeGesture
. Is this method supposed to be called by the framework or can this be manually called as well ? I have a use case where I have react native views on top of native views. Whenever a touch event is intercepted by ReactRootView
it starts dispatching it to JavaScript but if that touch event is to be handled by one of my Native Views, I only want the Native Views to handle it. But in the correct scenario due to this implementation, it ends up being handled by both. How do I handle this gracefully ?
This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.
This issue was closed because it has been stalled for 7 days with no activity.