react-native 在Android中,当触摸移动被子视图的本地手势拦截时,触摸移动会被取消,

z9ju0rcb  于 3个月前  发布在  React
关注(0)|答案(4)|浏览(72)

描述

嘿!我不确定这是否算作一个bug,但我在触摸事件处理中可能遗漏了一些功能。目前,在Android touchMove 中,当原生手势被识别并在子组件中拦截时,事件似乎会被取消。在查看您的源代码后,我注意到这是故意在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;
  }

我仍然希望在手势开始和结束时接收touchMove和特定的touchEnd事件。但是,现在我只会遇到几个touchMove事件和touchCancelled。实现起来似乎并不困难,但也许有原因为什么选择这种方法?

重现步骤

  1. 简单初始化应用程序 npx react-native@latest init AwesomeProject22
  2. 在顶层视图上添加一个简单的onTouchMove onTouchMove={()=>console.log("moving")}
  3. npx react-native run-android运行应用程序
  4. 尝试触发touch move事件。当向两边移动时,一切似乎都正常。当你开始拖动到顶部或底部时,只会触发几个touchMove事件,然后在下一个touchStart事件之前被取消。

React Native版本

0.74.1

受影响的平台

运行时 - Android

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

堆栈跟踪或日志

No crashes or failures recorded.

可复现问题

https://github.com/AndriusZal/44594-Reproducer

截图和视频

  • 无响应*
sc4hvdpw

sc4hvdpw1#

我认为在这个例子中不需要复制器,但我可以在进一步要求时创建它。

xxls0lw8

xxls0lw82#

我认为在这个例子中不需要复制器,但我可以在进一步要求时创建它。
请这样做。当我们调查这个问题时,这将节省我们的时间

cngwdvgl

cngwdvgl3#

已添加一个复现器: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.
我不介意自己提供修复,我只是可能需要一些背景信息来了解为什么选择这种方法。

vngu2lb8

vngu2lb84#

我的评论可能与上述问题无关,但我对onChildStartedNativeGesture的使用有一个疑问。这个方法是应该由框架调用的,还是也可以手动调用?我有一个用例,其中在原生视图上有一些React Native视图。每当一个触摸事件被ReactRootView拦截并开始分发给JavaScript时,如果这个触摸事件需要由我的一个原生视图处理,我只希望原生视图处理它。但在正确的场景下,由于这种实现方式,它最终被两者都处理了。我该如何优雅地处理这个问题呢?

相关问题