react-native-gesture-handler 3.0.0 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/RNGestureHandler.podspec +1 -1
- package/android/build.gradle +6 -5
- package/android/gradle.properties +1 -1
- package/android/src/main/java/com/swmansion/gesturehandler/core/FlingGestureHandler.kt +1 -1
- package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt +28 -32
- package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt +44 -6
- package/android/src/main/java/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt +4 -3
- package/android/src/main/java/com/swmansion/gesturehandler/core/NativeViewGestureHandler.kt +0 -13
- package/android/src/main/java/com/swmansion/gesturehandler/core/PanGestureHandler.kt +1 -1
- package/android/src/main/java/com/swmansion/gesturehandler/core/TapGestureHandler.kt +1 -1
- package/android/src/main/java/com/swmansion/gesturehandler/react/Extensions.kt +3 -0
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +30 -3
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt +4 -0
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt +8 -6
- package/apple/Handlers/RNNativeViewHandler.mm +4 -1
- package/apple/RNGestureHandlerButton.h +5 -0
- package/apple/RNGestureHandlerButtonComponentView.mm +38 -0
- package/apple/RNGestureHandlerDetector.h +0 -2
- package/apple/RNGestureHandlerDetector.mm +6 -6
- package/apple/RNGestureHandlerManager.h +5 -0
- package/apple/RNGestureHandlerManager.mm +14 -12
- package/lib/module/components/Pressable/Pressable.js +6 -2
- package/lib/module/components/Pressable/Pressable.js.map +1 -1
- package/lib/module/components/Pressable/StateMachine.js +10 -1
- package/lib/module/components/Pressable/StateMachine.js.map +1 -1
- package/lib/module/components/Pressable/stateDefinitions.js +3 -2
- package/lib/module/components/Pressable/stateDefinitions.js.map +1 -1
- package/lib/module/components/Pressable/utils.js +32 -1
- package/lib/module/components/Pressable/utils.js.map +1 -1
- package/lib/module/components/ReanimatedDrawerLayout.js +5 -4
- package/lib/module/components/ReanimatedDrawerLayout.js.map +1 -1
- package/lib/module/components/ReanimatedSwipeable/ReanimatedSwipeable.js +8 -2
- package/lib/module/components/ReanimatedSwipeable/ReanimatedSwipeable.js.map +1 -1
- package/lib/module/components/utils.js +14 -0
- package/lib/module/components/utils.js.map +1 -1
- package/lib/module/handlers/gestures/GestureDetector/utils.js +6 -6
- package/lib/module/handlers/gestures/GestureDetector/utils.js.map +1 -1
- package/lib/module/handlers/gestures/gesture.js +8 -0
- package/lib/module/handlers/gestures/gesture.js.map +1 -1
- package/lib/module/handlers/gestures/gestureComposition.js +14 -2
- package/lib/module/handlers/gestures/gestureComposition.js.map +1 -1
- package/lib/module/v3/components/GestureButtons.js +3 -0
- package/lib/module/v3/components/GestureButtons.js.map +1 -1
- package/lib/module/v3/components/Pressable.js +24 -5
- package/lib/module/v3/components/Pressable.js.map +1 -1
- package/lib/module/v3/components/Touchable/Touchable.js +3 -0
- package/lib/module/v3/components/Touchable/Touchable.js.map +1 -1
- package/lib/module/v3/hooks/utils/configUtils.js +3 -3
- package/lib/module/v3/hooks/utils/configUtils.js.map +1 -1
- package/lib/module/v3/hooks/utils/propsWhiteList.js +7 -6
- package/lib/module/v3/hooks/utils/propsWhiteList.js.map +1 -1
- package/lib/module/v3/hooks/utils/reanimatedUtils.js +8 -10
- package/lib/module/v3/hooks/utils/reanimatedUtils.js.map +1 -1
- package/lib/module/web/tools/GestureHandlerWebDelegate.js +5 -4
- package/lib/module/web/tools/GestureHandlerWebDelegate.js.map +1 -1
- package/lib/typescript/components/Pressable/Pressable.d.ts.map +1 -1
- package/lib/typescript/components/Pressable/StateMachine.d.ts +1 -0
- package/lib/typescript/components/Pressable/StateMachine.d.ts.map +1 -1
- package/lib/typescript/components/Pressable/stateDefinitions.d.ts.map +1 -1
- package/lib/typescript/components/Pressable/utils.d.ts +2 -1
- package/lib/typescript/components/Pressable/utils.d.ts.map +1 -1
- package/lib/typescript/components/ReanimatedDrawerLayout.d.ts +14 -2
- package/lib/typescript/components/ReanimatedDrawerLayout.d.ts.map +1 -1
- package/lib/typescript/components/ReanimatedSwipeable/ReanimatedSwipeable.d.ts.map +1 -1
- package/lib/typescript/components/utils.d.ts +11 -0
- package/lib/typescript/components/utils.d.ts.map +1 -1
- package/lib/typescript/handlers/gestures/GestureDetector/utils.d.ts +4 -4
- package/lib/typescript/handlers/gestures/GestureDetector/utils.d.ts.map +1 -1
- package/lib/typescript/handlers/gestures/gesture.d.ts +4 -0
- package/lib/typescript/handlers/gestures/gesture.d.ts.map +1 -1
- package/lib/typescript/handlers/gestures/gestureComposition.d.ts.map +1 -1
- package/lib/typescript/v3/components/GestureButtons.d.ts.map +1 -1
- package/lib/typescript/v3/components/Pressable.d.ts.map +1 -1
- package/lib/typescript/v3/components/Touchable/Touchable.d.ts.map +1 -1
- package/lib/typescript/v3/hooks/utils/configUtils.d.ts.map +1 -1
- package/lib/typescript/v3/hooks/utils/propsWhiteList.d.ts.map +1 -1
- package/lib/typescript/v3/hooks/utils/reanimatedUtils.d.ts.map +1 -1
- package/lib/typescript/web/tools/GestureHandlerWebDelegate.d.ts.map +1 -1
- package/package.json +6 -6
- package/scripts/gesture_handler_utils.rb +23 -17
- package/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerDetectorShadowNode.cpp +19 -0
- package/shared/shadowNodes/react/renderer/components/rngesturehandler_codegen/RNGestureHandlerDetectorShadowNode.h +1 -0
- package/src/components/Pressable/Pressable.tsx +9 -1
- package/src/components/Pressable/StateMachine.tsx +16 -1
- package/src/components/Pressable/stateDefinitions.ts +3 -2
- package/src/components/Pressable/utils.ts +37 -0
- package/src/components/ReanimatedDrawerLayout.tsx +27 -8
- package/src/components/ReanimatedSwipeable/ReanimatedSwipeable.tsx +8 -2
- package/src/components/utils.ts +22 -0
- package/src/handlers/gestures/GestureDetector/utils.ts +6 -10
- package/src/handlers/gestures/gesture.ts +11 -0
- package/src/handlers/gestures/gestureComposition.ts +15 -2
- package/src/v3/components/GestureButtons.tsx +4 -0
- package/src/v3/components/Pressable.tsx +33 -3
- package/src/v3/components/Touchable/Touchable.tsx +4 -0
- package/src/v3/hooks/utils/configUtils.ts +4 -5
- package/src/v3/hooks/utils/propsWhiteList.ts +6 -6
- package/src/v3/hooks/utils/reanimatedUtils.ts +9 -10
- package/src/web/tools/GestureHandlerWebDelegate.ts +10 -4
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<img src="https://user-images.githubusercontent.com/16062886/117444014-2d1ffd80-af39-11eb-9bbb-33c320599d93.png" width="100%" alt="React Native Gesture Handler by Software Mansion">
|
|
2
2
|
|
|
3
|
+
[](https://swm-delivery.com/www/delivery/ck-slug.php?zoneid=zone-gh-react-native-gesture-handler-1&n=1)
|
|
4
|
+
[](https://swm-delivery.com/www/delivery/ck-slug.php?zoneid=zone-gh-react-native-gesture-handler-2&n=1)
|
|
5
|
+
[](https://swm-delivery.com/www/delivery/ck-slug.php?zoneid=zone-gh-react-native-gesture-handler-3&n=1)
|
|
6
|
+
|
|
3
7
|
### Declarative API exposing platform native touch and gesture system to React Native.
|
|
4
8
|
|
|
5
9
|
React Native Gesture Handler provides native-driven gesture management APIs for building best possible touch-based experiences in React Native.
|
package/RNGestureHandler.podspec
CHANGED
|
@@ -5,7 +5,7 @@ is_gh_example_app = ENV["GH_EXAMPLE_APP_NAME"] != nil
|
|
|
5
5
|
|
|
6
6
|
compilation_metadata_dir = "CompilationDatabase"
|
|
7
7
|
compilation_metadata_generation_flag = is_gh_example_app ? '-gen-cdb-fragment-path ' + compilation_metadata_dir : ''
|
|
8
|
-
version_flag = "-DREACT_NATIVE_MINOR_VERSION=#{get_react_native_minor_version()}"
|
|
8
|
+
version_flag = "-DREACT_NATIVE_MINOR_VERSION=#{GestureHandlerUtils.get_react_native_minor_version()}"
|
|
9
9
|
|
|
10
10
|
Pod::Spec.new do |s|
|
|
11
11
|
# NPM package specification
|
package/android/build.gradle
CHANGED
|
@@ -2,17 +2,18 @@ import groovy.json.JsonSlurper
|
|
|
2
2
|
import com.android.build.gradle.tasks.ExternalNativeBuildJsonTask
|
|
3
3
|
|
|
4
4
|
buildscript {
|
|
5
|
-
def kotlin_version = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : project.properties['RNGH_kotlinVersion']
|
|
6
|
-
|
|
7
5
|
repositories {
|
|
8
6
|
mavenCentral()
|
|
9
7
|
google()
|
|
10
8
|
}
|
|
11
9
|
|
|
12
10
|
dependencies {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
if (project == rootProject) {
|
|
12
|
+
def kotlin_version = project.properties['RNGH_kotlinVersion']
|
|
13
|
+
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
|
|
14
|
+
classpath("com.android.tools.build:gradle:8.10.1")
|
|
15
|
+
classpath("com.diffplug.spotless:spotless-plugin-gradle:7.0.4")
|
|
16
|
+
}
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
19
|
|
|
@@ -16,4 +16,4 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemor
|
|
|
16
16
|
# This option should only be used with decoupled projects. More details, visit
|
|
17
17
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
|
18
18
|
# org.gradle.parallel=true
|
|
19
|
-
RNGH_kotlinVersion=2.0
|
|
19
|
+
RNGH_kotlinVersion=2.2.0
|
|
@@ -4,7 +4,6 @@ import android.app.Activity
|
|
|
4
4
|
import android.content.Context
|
|
5
5
|
import android.content.ContextWrapper
|
|
6
6
|
import android.graphics.PointF
|
|
7
|
-
import android.os.Build
|
|
8
7
|
import android.view.MotionEvent
|
|
9
8
|
import android.view.MotionEvent.PointerCoords
|
|
10
9
|
import android.view.MotionEvent.PointerProperties
|
|
@@ -411,7 +410,10 @@ open class GestureHandler {
|
|
|
411
410
|
}
|
|
412
411
|
}
|
|
413
412
|
|
|
414
|
-
numberOfPointers = adaptedTransformedEvent.
|
|
413
|
+
numberOfPointers = when (adaptedTransformedEvent.actionMasked) {
|
|
414
|
+
MotionEvent.ACTION_POINTER_UP -> adaptedTransformedEvent.pointerCount - 1
|
|
415
|
+
else -> adaptedTransformedEvent.pointerCount
|
|
416
|
+
}
|
|
415
417
|
|
|
416
418
|
x = adaptedTransformedEvent.x
|
|
417
419
|
y = adaptedTransformedEvent.y
|
|
@@ -820,44 +822,38 @@ open class GestureHandler {
|
|
|
820
822
|
return clickedButton and mouseButton != 0
|
|
821
823
|
}
|
|
822
824
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
825
|
+
// Decides whether the gesture should ignore this event. While using a mouse we receive both the
|
|
826
|
+
// touch-compatible stream (ACTION_DOWN/UP/...) and the BUTTON_* events, so we act on only the
|
|
827
|
+
// latter, and we drop events coming from a button other than the configured `mouseButton`.
|
|
828
|
+
// Non-mouse input is never skipped here.
|
|
829
|
+
protected fun shouldSkipEvent(sourceEvent: MotionEvent): Boolean {
|
|
830
|
+
if (sourceEvent.getToolType(0) != MotionEvent.TOOL_TYPE_MOUSE) {
|
|
831
|
+
return false
|
|
832
|
+
}
|
|
826
833
|
|
|
827
834
|
with(sourceEvent) {
|
|
828
|
-
//
|
|
829
|
-
if (
|
|
830
|
-
|
|
835
|
+
// While using mouse, we want to ignore default events for touch.
|
|
836
|
+
if (actionMasked == MotionEvent.ACTION_DOWN ||
|
|
837
|
+
actionMasked == MotionEvent.ACTION_UP ||
|
|
838
|
+
actionMasked == MotionEvent.ACTION_POINTER_UP ||
|
|
839
|
+
actionMasked == MotionEvent.ACTION_POINTER_DOWN
|
|
831
840
|
) {
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
action == MotionEvent.ACTION_UP ||
|
|
835
|
-
action == MotionEvent.ACTION_POINTER_UP ||
|
|
836
|
-
action == MotionEvent.ACTION_POINTER_DOWN
|
|
837
|
-
) {
|
|
838
|
-
return@shouldActivateWithMouse false
|
|
839
|
-
}
|
|
841
|
+
return@shouldSkipEvent true
|
|
842
|
+
}
|
|
840
843
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
844
|
+
// Skip events from a button other than the configured one. For BUTTON_* events the clicked
|
|
845
|
+
// button is read from `actionButton`.
|
|
846
|
+
if (actionMasked != MotionEvent.ACTION_MOVE && !isButtonInConfig(actionButton)) {
|
|
847
|
+
return@shouldSkipEvent true
|
|
848
|
+
}
|
|
845
849
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
}
|
|
850
|
-
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
|
851
|
-
// We do not fully support mouse below API 23, so we will ignore BUTTON events.
|
|
852
|
-
if (action == MotionEvent.ACTION_BUTTON_PRESS ||
|
|
853
|
-
action == MotionEvent.ACTION_BUTTON_RELEASE
|
|
854
|
-
) {
|
|
855
|
-
return@shouldActivateWithMouse false
|
|
856
|
-
}
|
|
850
|
+
// For ACTION_MOVE the pressed button is read from `buttonState`.
|
|
851
|
+
if (actionMasked == MotionEvent.ACTION_MOVE && !isButtonInConfig(buttonState)) {
|
|
852
|
+
return@shouldSkipEvent true
|
|
857
853
|
}
|
|
858
854
|
}
|
|
859
855
|
|
|
860
|
-
return
|
|
856
|
+
return false
|
|
861
857
|
}
|
|
862
858
|
|
|
863
859
|
/**
|
package/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt
CHANGED
|
@@ -492,7 +492,7 @@ class GestureHandlerOrchestrator(
|
|
|
492
492
|
top + view.height > parent.height
|
|
493
493
|
}
|
|
494
494
|
|
|
495
|
-
private fun extractAncestorHandlers(view: View, coords: FloatArray, pointerId: Int): Boolean {
|
|
495
|
+
private fun extractAncestorHandlers(view: View, coords: FloatArray, pointerId: Int, event: MotionEvent): Boolean {
|
|
496
496
|
var found = false
|
|
497
497
|
var parent = view.parent
|
|
498
498
|
|
|
@@ -509,6 +509,10 @@ class GestureHandlerOrchestrator(
|
|
|
509
509
|
handlerRegistry.getHandlersForView(parent)?.let {
|
|
510
510
|
synchronized(it) {
|
|
511
511
|
for (handler in it) {
|
|
512
|
+
if (shouldHandlerSkipHoverEvents(handler, event)) {
|
|
513
|
+
continue
|
|
514
|
+
}
|
|
515
|
+
|
|
512
516
|
if (handler.isEnabled && handler.isWithinBounds(view, coords[0], coords[1])) {
|
|
513
517
|
found = true
|
|
514
518
|
recordHandlerIfNotPresent(handler, parentViewGroup)
|
|
@@ -542,13 +546,33 @@ class GestureHandlerOrchestrator(
|
|
|
542
546
|
coords: FloatArray,
|
|
543
547
|
pointerId: Int,
|
|
544
548
|
event: MotionEvent,
|
|
549
|
+
useChildBounds: Boolean = false,
|
|
545
550
|
): Boolean {
|
|
551
|
+
var boundsView = view
|
|
552
|
+
var boundsX = coords[0]
|
|
553
|
+
var boundsY = coords[1]
|
|
554
|
+
|
|
555
|
+
// When `useChildBounds` is set, handler bounds are checked in the coordinate space of the view's
|
|
556
|
+
// single child instead of against the view itself. The caller only sets this for a native detector
|
|
557
|
+
// with exactly one child, so its interactive area follows the child's transforms (e.g. `translateX`)
|
|
558
|
+
// rather than the detector's transform-agnostic frame. For an identity transform the child fills the
|
|
559
|
+
// detector, so this matches the detector's own frame and `hitSlop` expansion (#4049) keeps working;
|
|
560
|
+
// for a translated child the area follows the content.
|
|
561
|
+
if (useChildBounds) {
|
|
562
|
+
val child = (view as RNGestureHandlerDetectorView).getChildAt(0)
|
|
563
|
+
val childPoint = tempPoint
|
|
564
|
+
transformPointToChildViewCoords(coords[0], coords[1], view, child, childPoint)
|
|
565
|
+
boundsView = child
|
|
566
|
+
boundsX = childPoint.x
|
|
567
|
+
boundsY = childPoint.y
|
|
568
|
+
}
|
|
569
|
+
|
|
546
570
|
var found = false
|
|
547
571
|
handlerRegistry.getHandlersForView(view)?.let {
|
|
548
572
|
synchronized(it) {
|
|
549
573
|
for (handler in it) {
|
|
550
574
|
// skip disabled and out-of-bounds handlers
|
|
551
|
-
if (!handler.isEnabled || !handler.isWithinBounds(
|
|
575
|
+
if (!handler.isEnabled || !handler.isWithinBounds(boundsView, boundsX, boundsY)) {
|
|
552
576
|
continue
|
|
553
577
|
}
|
|
554
578
|
|
|
@@ -568,15 +592,21 @@ class GestureHandlerOrchestrator(
|
|
|
568
592
|
if (coords[0] in 0f..view.width.toFloat() &&
|
|
569
593
|
coords[1] in 0f..view.height.toFloat() &&
|
|
570
594
|
isViewOverflowingParent(view) &&
|
|
571
|
-
extractAncestorHandlers(view, coords, pointerId)
|
|
595
|
+
extractAncestorHandlers(view, coords, pointerId, event)
|
|
572
596
|
) {
|
|
573
597
|
found = true
|
|
574
598
|
}
|
|
575
599
|
|
|
576
600
|
if (view is ReactCompoundView) {
|
|
577
|
-
|
|
601
|
+
// Some implementations (e.g. RNScreens' DimmingView) intentionally throw from `reactTagForTouch`
|
|
602
|
+
val tagForCoords =
|
|
603
|
+
try {
|
|
604
|
+
view.reactTagForTouch(coords[0], coords[1])
|
|
605
|
+
} catch (e: IllegalStateException) {
|
|
606
|
+
null
|
|
607
|
+
}
|
|
578
608
|
|
|
579
|
-
if (tagForCoords != view.id) {
|
|
609
|
+
if (tagForCoords != null && tagForCoords != view.id) {
|
|
580
610
|
handlerRegistry.getHandlersForViewWithTag(tagForCoords)?.let {
|
|
581
611
|
synchronized(it) {
|
|
582
612
|
for (handler in it) {
|
|
@@ -680,8 +710,16 @@ class GestureHandlerOrchestrator(
|
|
|
680
710
|
is ViewGroup -> {
|
|
681
711
|
extractGestureHandlers(view, coords, pointerId, event).also { found ->
|
|
682
712
|
// A child view is handling touch, also extract handlers attached to this view
|
|
683
|
-
if (found
|
|
713
|
+
if (found) {
|
|
684
714
|
recordViewHandlersForPointer(view, coords, pointerId, event)
|
|
715
|
+
} else if (view is RNGestureHandlerDetectorView) {
|
|
716
|
+
// No child consumed the touch, but we still record the detector's own handlers so
|
|
717
|
+
// that `hitSlop` expansion keeps working. The detector's frame ignores
|
|
718
|
+
// child transforms, so for a single-child detector we check bounds in the child's
|
|
719
|
+
// transform-aware coordinate space - otherwise the detector would steal presses over
|
|
720
|
+
// areas its content has been moved away from.
|
|
721
|
+
val useChildBounds = view.childCount == 1
|
|
722
|
+
recordViewHandlersForPointer(view, coords, pointerId, event, useChildBounds)
|
|
685
723
|
}
|
|
686
724
|
}
|
|
687
725
|
}
|
|
@@ -71,7 +71,7 @@ class LongPressGestureHandler(context: Context) : GestureHandler() {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) {
|
|
74
|
-
if (
|
|
74
|
+
if (shouldSkipEvent(sourceEvent)) {
|
|
75
75
|
return
|
|
76
76
|
}
|
|
77
77
|
|
|
@@ -108,7 +108,8 @@ class LongPressGestureHandler(context: Context) : GestureHandler() {
|
|
|
108
108
|
currentPointers == numberOfPointersRequired &&
|
|
109
109
|
(
|
|
110
110
|
sourceEvent.actionMasked == MotionEvent.ACTION_DOWN ||
|
|
111
|
-
sourceEvent.actionMasked == MotionEvent.ACTION_POINTER_DOWN
|
|
111
|
+
sourceEvent.actionMasked == MotionEvent.ACTION_POINTER_DOWN ||
|
|
112
|
+
sourceEvent.actionMasked == MotionEvent.ACTION_BUTTON_PRESS
|
|
112
113
|
)
|
|
113
114
|
) {
|
|
114
115
|
handler = Handler(Looper.getMainLooper())
|
|
@@ -199,7 +200,7 @@ class LongPressGestureHandler(context: Context) : GestureHandler() {
|
|
|
199
200
|
handler.maxDist = PixelUtil.toPixelFromDIP(config.getDouble(KEY_MAX_DIST))
|
|
200
201
|
}
|
|
201
202
|
if (config.hasKey(KEY_NUMBER_OF_POINTERS)) {
|
|
202
|
-
handler.
|
|
203
|
+
handler.numberOfPointersRequired = config.getInt(KEY_NUMBER_OF_POINTERS)
|
|
203
204
|
}
|
|
204
205
|
}
|
|
205
206
|
|
|
@@ -14,10 +14,8 @@ import com.facebook.react.views.swiperefresh.ReactSwipeRefreshLayout
|
|
|
14
14
|
import com.facebook.react.views.text.ReactTextView
|
|
15
15
|
import com.facebook.react.views.textinput.ReactEditText
|
|
16
16
|
import com.facebook.react.views.view.ReactViewGroup
|
|
17
|
-
import com.swmansion.gesturehandler.react.RNGestureHandlerButtonViewManager
|
|
18
17
|
import com.swmansion.gesturehandler.react.RNGestureHandlerRootHelper
|
|
19
18
|
import com.swmansion.gesturehandler.react.events.eventbuilders.NativeGestureHandlerEventDataBuilder
|
|
20
|
-
import com.swmansion.gesturehandler.react.isScreenReaderOn
|
|
21
19
|
|
|
22
20
|
class NativeViewGestureHandler : GestureHandler() {
|
|
23
21
|
override val isContinuous = true
|
|
@@ -121,17 +119,6 @@ class NativeViewGestureHandler : GestureHandler() {
|
|
|
121
119
|
|
|
122
120
|
override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) {
|
|
123
121
|
val view = view!!
|
|
124
|
-
|
|
125
|
-
val isTouchExplorationEnabled = view.context.isScreenReaderOn()
|
|
126
|
-
|
|
127
|
-
if (view is RNGestureHandlerButtonViewManager.ButtonViewGroup && isTouchExplorationEnabled) {
|
|
128
|
-
// Fix for: https://github.com/software-mansion/react-native-gesture-handler/issues/2808
|
|
129
|
-
// When TalkBack is enabled, events are often not being sent to the orchestrator for processing.
|
|
130
|
-
// Instead, states will be changed directly by an alternative mechanism added in this PR:
|
|
131
|
-
// https://github.com/software-mansion/react-native-gesture-handler/pull/2234
|
|
132
|
-
return
|
|
133
|
-
}
|
|
134
|
-
|
|
135
122
|
if (event.actionMasked == MotionEvent.ACTION_UP) {
|
|
136
123
|
if (state == STATE_UNDETERMINED && !hook.canBegin(event)) {
|
|
137
124
|
cancel()
|
|
@@ -160,7 +160,7 @@ class PanGestureHandler(context: Context?) : GestureHandler() {
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) {
|
|
163
|
-
if (
|
|
163
|
+
if (shouldSkipEvent(sourceEvent)) {
|
|
164
164
|
return
|
|
165
165
|
}
|
|
166
166
|
|
|
@@ -17,6 +17,9 @@ fun MotionEvent.isHoverAction(): Boolean = action == MotionEvent.ACTION_HOVER_MO
|
|
|
17
17
|
action == MotionEvent.ACTION_HOVER_ENTER ||
|
|
18
18
|
action == MotionEvent.ACTION_HOVER_EXIT
|
|
19
19
|
|
|
20
|
+
fun MotionEvent.isButtonAction(): Boolean = actionMasked == MotionEvent.ACTION_BUTTON_PRESS ||
|
|
21
|
+
actionMasked == MotionEvent.ACTION_BUTTON_RELEASE
|
|
22
|
+
|
|
20
23
|
val Display.minimumFrameTime: Float
|
|
21
24
|
get() {
|
|
22
25
|
val supportedModes = this.supportedModes
|
|
@@ -27,6 +27,7 @@ import androidx.core.view.children
|
|
|
27
27
|
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
|
28
28
|
import com.facebook.react.R
|
|
29
29
|
import com.facebook.react.bridge.Dynamic
|
|
30
|
+
import com.facebook.react.bridge.ReadableArray
|
|
30
31
|
import com.facebook.react.module.annotations.ReactModule
|
|
31
32
|
import com.facebook.react.uimanager.BackgroundStyleApplicator
|
|
32
33
|
import com.facebook.react.uimanager.LengthPercentage
|
|
@@ -347,6 +348,7 @@ class RNGestureHandlerButtonViewManager :
|
|
|
347
348
|
super.onAfterUpdateTransaction(view)
|
|
348
349
|
|
|
349
350
|
view.updateBackground()
|
|
351
|
+
view.updateLongPressAccessibility()
|
|
350
352
|
}
|
|
351
353
|
|
|
352
354
|
override fun getDelegate(): ViewManagerDelegate<ButtonViewGroup>? = mDelegate
|
|
@@ -434,6 +436,23 @@ class RNGestureHandlerButtonViewManager :
|
|
|
434
436
|
invalidate()
|
|
435
437
|
}
|
|
436
438
|
|
|
439
|
+
fun updateLongPressAccessibility() {
|
|
440
|
+
val hasLongPress = hasLongPressAccessibilityAction()
|
|
441
|
+
setOnLongClickListener(if (hasLongPress) dummyLongClickListener else null)
|
|
442
|
+
isLongClickable = hasLongPress
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
private fun hasLongPressAccessibilityAction(): Boolean {
|
|
446
|
+
val actions = getTag(R.id.accessibility_actions) as? ReadableArray ?: return false
|
|
447
|
+
for (i in 0 until actions.size()) {
|
|
448
|
+
if (actions.getMap(i)?.getString("name") == "longpress") {
|
|
449
|
+
return true
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return false
|
|
454
|
+
}
|
|
455
|
+
|
|
437
456
|
override fun setBackgroundColor(color: Int) {
|
|
438
457
|
BackgroundStyleApplicator.setBackgroundColor(this, color)
|
|
439
458
|
}
|
|
@@ -876,10 +895,11 @@ class RNGestureHandlerButtonViewManager :
|
|
|
876
895
|
}
|
|
877
896
|
|
|
878
897
|
override fun performClick(): Boolean {
|
|
879
|
-
// don't
|
|
898
|
+
// don't perform click when a child button is pressed (mainly to prevent sound effect of
|
|
880
899
|
// a parent button from playing)
|
|
881
900
|
return if (!isChildTouched()) {
|
|
882
|
-
|
|
901
|
+
// Don't activate native handlers when isPressed is true (motion events are passing through)
|
|
902
|
+
if (context.isScreenReaderOn() && !isPressed) {
|
|
883
903
|
RNGestureHandlerRootView.findGestureHandlerRootView(this)?.activateNativeHandlers(this)
|
|
884
904
|
} else if (receivedKeyEvent) {
|
|
885
905
|
RNGestureHandlerRootView.findGestureHandlerRootView(this)?.activateNativeHandlers(this)
|
|
@@ -936,7 +956,14 @@ class RNGestureHandlerButtonViewManager :
|
|
|
936
956
|
var resolveOutValue = TypedValue()
|
|
937
957
|
var touchResponder: ButtonViewGroup? = null
|
|
938
958
|
var soundResponder: ButtonViewGroup? = null
|
|
939
|
-
|
|
959
|
+
val dummyClickListener = OnClickListener { }
|
|
960
|
+
val dummyLongClickListener = OnLongClickListener { view ->
|
|
961
|
+
if (view.context.isScreenReaderOn()) {
|
|
962
|
+
view.performAccessibilityAction(AccessibilityNodeInfo.ACTION_LONG_CLICK, null)
|
|
963
|
+
} else {
|
|
964
|
+
false
|
|
965
|
+
}
|
|
966
|
+
}
|
|
940
967
|
}
|
|
941
968
|
}
|
|
942
969
|
|
package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt
CHANGED
|
@@ -47,6 +47,10 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
fun setModuleId(id: Int) {
|
|
50
|
+
if (this.moduleId == id) {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
50
54
|
assert(this.moduleId == -1) { "Tried to change moduleId of a native detector" }
|
|
51
55
|
|
|
52
56
|
this.moduleId = id
|
package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt
CHANGED
|
@@ -62,12 +62,14 @@ class RNGestureHandlerRootView(context: Context?) : ReactViewGroup(context) {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
override fun dispatchGenericMotionEvent(ev: MotionEvent) =
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
override fun dispatchGenericMotionEvent(ev: MotionEvent) = if (rootViewEnabled &&
|
|
66
|
+
(ev.isHoverAction() || ev.isButtonAction()) &&
|
|
67
|
+
rootHelper!!.dispatchTouchEvent(ev)
|
|
68
|
+
) {
|
|
69
|
+
true
|
|
70
|
+
} else {
|
|
71
|
+
super.dispatchGenericMotionEvent(ev)
|
|
72
|
+
}
|
|
71
73
|
|
|
72
74
|
override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
|
|
73
75
|
if (rootViewEnabled) {
|
|
@@ -145,10 +145,13 @@
|
|
|
145
145
|
// Pressing UISwitch triggers only touchUp and valueChanged callbacks. In order to align its behavior
|
|
146
146
|
// with other UIControls, we have to dispatch full Gesture Handler events flow in one callback, as
|
|
147
147
|
// touchesDown is not executed.
|
|
148
|
+
#if !TARGET_OS_TV
|
|
148
149
|
if ([view isKindOfClass:[UISwitch class]]) {
|
|
149
150
|
_pointerType = RNGestureHandlerTouch;
|
|
150
151
|
[control addTarget:self action:@selector(handleSwitch:) forControlEvents:UIControlEventValueChanged];
|
|
151
|
-
} else
|
|
152
|
+
} else
|
|
153
|
+
#endif // !TARGET_OS_TV
|
|
154
|
+
{
|
|
152
155
|
[control addTarget:self action:@selector(handleTouchDown:forEvent:) forControlEvents:UIControlEventTouchDown];
|
|
153
156
|
[control addTarget:self
|
|
154
157
|
action:@selector(handleTouchUpOutside:forEvent:)
|
|
@@ -51,6 +51,11 @@
|
|
|
51
51
|
*/
|
|
52
52
|
- (void)applyStartAnimationState;
|
|
53
53
|
|
|
54
|
+
#if TARGET_OS_TV
|
|
55
|
+
- (void)handleAnimatePressIn;
|
|
56
|
+
- (void)handleAnimatePressOut;
|
|
57
|
+
#endif // TARGET_OS_TV
|
|
58
|
+
|
|
54
59
|
/**
|
|
55
60
|
* Resets all transient press/animation state so the button can be safely reused
|
|
56
61
|
* by Fabric view recycling. Cancels pending press-out blocks, removes in-flight
|
|
@@ -68,6 +68,44 @@ static RNGestureHandlerPointerEvents RCTPointerEventsToEnum(facebook::react::Poi
|
|
|
68
68
|
return self;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
#if TARGET_OS_TV
|
|
72
|
+
- (void)emitPressInEvent
|
|
73
|
+
{
|
|
74
|
+
if (!_buttonView.userEnabled) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
[_buttonView sendActionsForControlEvents:UIControlEventTouchDown];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
- (void)emitPressOutEvent
|
|
82
|
+
{
|
|
83
|
+
if (!_buttonView.userEnabled) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
[_buttonView sendActionsForControlEvents:UIControlEventTouchUpInside];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
- (void)animatePressIn
|
|
91
|
+
{
|
|
92
|
+
if (!_buttonView.userEnabled) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
[_buttonView handleAnimatePressIn];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
- (void)animatePressOut
|
|
100
|
+
{
|
|
101
|
+
if (!_buttonView.userEnabled) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
[_buttonView handleAnimatePressOut];
|
|
106
|
+
}
|
|
107
|
+
#endif // TARGET_OS_TV
|
|
108
|
+
|
|
71
109
|
- (void)prepareForRecycle
|
|
72
110
|
{
|
|
73
111
|
[self.layer removeAnimationForKey:@"transform"];
|
|
@@ -254,14 +254,14 @@
|
|
|
254
254
|
withHostDetector:self];
|
|
255
255
|
} else {
|
|
256
256
|
// Hierarchy was folded into a single UIView.
|
|
257
|
-
[manager
|
|
257
|
+
[manager attachHandlerForDetectorWithTag:handler.tag toView:self withActionType:actionType withHostDetector:self];
|
|
258
258
|
handler.virtualViewTag = @(viewTag);
|
|
259
259
|
}
|
|
260
260
|
[_attachedHandlers addObject:handler.tag];
|
|
261
261
|
return;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
[manager
|
|
264
|
+
[manager attachHandlerForDetectorWithTag:handler.tag toView:self withActionType:actionType withHostDetector:self];
|
|
265
265
|
[_attachedHandlers addObject:handler.tag];
|
|
266
266
|
}
|
|
267
267
|
|
|
@@ -351,10 +351,10 @@
|
|
|
351
351
|
if ([handlerManager.registry handlerWithTag:handlerTag] == nil) {
|
|
352
352
|
continue;
|
|
353
353
|
}
|
|
354
|
-
[handlerManager
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
354
|
+
[handlerManager attachHandlerForDetectorWithTag:handlerTag
|
|
355
|
+
toView:view
|
|
356
|
+
withActionType:RNGestureHandlerActionTypeNativeDetector
|
|
357
|
+
withHostDetector:self];
|
|
358
358
|
[_attachedHandlers addObject:handlerTag];
|
|
359
359
|
}
|
|
360
360
|
}
|
|
@@ -29,6 +29,11 @@
|
|
|
29
29
|
withActionType:(RNGestureHandlerActionType)actionType
|
|
30
30
|
withHostDetector:(nullable RNGHUIView *)hostDetector;
|
|
31
31
|
|
|
32
|
+
- (void)attachHandlerForDetectorWithTag:(nonnull NSNumber *)handlerTag
|
|
33
|
+
toView:(nonnull RNGHUIView *)view
|
|
34
|
+
withActionType:(RNGestureHandlerActionType)actionType
|
|
35
|
+
withHostDetector:(nullable RNGHUIView *)hostDetector;
|
|
36
|
+
|
|
32
37
|
- (void)setGestureHandlerConfig:(nonnull NSNumber *)handlerTag config:(nonnull NSDictionary *)config;
|
|
33
38
|
|
|
34
39
|
- (void)updateGestureHandlerConfig:(nonnull NSNumber *)handlerTag config:(nonnull NSDictionary *)config;
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
#import <React/RCTEventDispatcherProtocol.h>
|
|
5
5
|
#import <React/RCTLog.h>
|
|
6
6
|
#import <React/RCTModalHostViewController.h>
|
|
7
|
-
#import <React/RCTRootContentView.h>
|
|
8
7
|
#import <React/RCTRootView.h>
|
|
9
8
|
#import <React/RCTUIManager.h>
|
|
10
9
|
#import <React/RCTViewManager.h>
|
|
@@ -210,6 +209,15 @@ constexpr int NEW_ARCH_NUMBER_OF_ATTACH_RETRIES = 25;
|
|
|
210
209
|
[self registerViewWithGestureRecognizerAttachedIfNeeded:view];
|
|
211
210
|
}
|
|
212
211
|
|
|
212
|
+
- (void)attachHandlerForDetectorWithTag:(nonnull NSNumber *)handlerTag
|
|
213
|
+
toView:(nonnull RNGHUIView *)view
|
|
214
|
+
withActionType:(RNGestureHandlerActionType)actionType
|
|
215
|
+
withHostDetector:(nullable RNGHUIView *)hostDetector
|
|
216
|
+
{
|
|
217
|
+
[_registry attachHandlerWithTag:handlerTag toView:view withActionType:actionType withHostDetector:hostDetector];
|
|
218
|
+
[self registerViewWithGestureRecognizerAttachedIfNeeded:view];
|
|
219
|
+
}
|
|
220
|
+
|
|
213
221
|
- (void)setGestureHandlerConfig:(NSNumber *)handlerTag config:(NSDictionary *)config
|
|
214
222
|
{
|
|
215
223
|
RNGestureHandler *handler = [_registry handlerWithTag:handlerTag];
|
|
@@ -472,11 +480,11 @@ constexpr int NEW_ARCH_NUMBER_OF_ATTACH_RETRIES = 25;
|
|
|
472
480
|
|
|
473
481
|
- (void)sendEventForNativeAnimatedEvent:(RNGestureHandlerStateChange *)event
|
|
474
482
|
{
|
|
475
|
-
// Delivers the event to
|
|
476
|
-
//
|
|
477
|
-
//
|
|
478
|
-
//
|
|
479
|
-
[
|
|
483
|
+
// Delivers the event to NativeAnimated[Turbo]Module via the dispatcher's
|
|
484
|
+
// observer mechanism. We don't go through sendEvent: because that also
|
|
485
|
+
// dispatches the event to JS via RCTEventEmitter.receiveEvent, which is no
|
|
486
|
+
// longer a registered callable module in RN 0.86+ (Fabric-only).
|
|
487
|
+
[_eventDispatcher notifyObserversOfEvent:event];
|
|
480
488
|
}
|
|
481
489
|
|
|
482
490
|
- (void)sendEventForJSFunctionOldAPI:(RNGestureHandlerStateChange *)event
|
|
@@ -491,12 +499,6 @@ constexpr int NEW_ARCH_NUMBER_OF_ATTACH_RETRIES = 25;
|
|
|
491
499
|
[self sendEventForDeviceEvent:event];
|
|
492
500
|
}
|
|
493
501
|
|
|
494
|
-
- (void)sendEventForDirectEvent:(RNGestureHandlerStateChange *)event
|
|
495
|
-
{
|
|
496
|
-
// Delivers the event to JS as a direct event.
|
|
497
|
-
[_eventDispatcher sendEvent:event];
|
|
498
|
-
}
|
|
499
|
-
|
|
500
502
|
- (void)sendEventForDeviceEvent:(RNGestureHandlerStateChange *)event
|
|
501
503
|
{
|
|
502
504
|
// Delivers the event to JS as a device event.
|