react-native-gesture-handler 2.4.0 → 2.5.0

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.
Files changed (120) hide show
  1. package/README.md +3 -2
  2. package/android/build.gradle +28 -4
  3. package/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandler.kt +9 -5
  4. package/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerOrchestrator.kt +6 -1
  5. package/android/lib/src/main/java/com/swmansion/gesturehandler/NativeViewGestureHandler.kt +103 -22
  6. package/android/lib/src/main/java/com/swmansion/gesturehandler/PanGestureHandler.kt +29 -2
  7. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +74 -84
  8. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt +4 -0
  9. package/android/src/main/jni/Android.mk +1 -2
  10. package/android/src/paper/java/com/facebook/react/viewmanagers/RNGestureHandlerButtonManagerDelegate.java +12 -9
  11. package/android/src/paper/java/com/facebook/react/viewmanagers/RNGestureHandlerButtonManagerInterface.java +1 -0
  12. package/ios/Handlers/RNFlingHandler.m +43 -1
  13. package/ios/Handlers/{RNNativeViewHandler.m → RNNativeViewHandler.mm} +13 -1
  14. package/ios/Handlers/RNPanHandler.m +27 -0
  15. package/ios/RNGestureHandler.h +1 -0
  16. package/ios/RNGestureHandler.m +22 -4
  17. package/ios/RNGestureHandlerManager.mm +10 -2
  18. package/ios/RNGestureHandlerModule.mm +4 -1
  19. package/ios/RNManualActivationRecognizer.m +10 -3
  20. package/ios/RNRootViewGestureRecognizer.m +12 -1
  21. package/lib/commonjs/RNGestureHandlerModule.macos.js +81 -0
  22. package/lib/commonjs/RNGestureHandlerModule.macos.js.map +1 -0
  23. package/lib/commonjs/components/DrawerLayout.js +38 -11
  24. package/lib/commonjs/components/DrawerLayout.js.map +1 -1
  25. package/lib/commonjs/components/GestureButtons.js.map +1 -1
  26. package/lib/commonjs/components/touchables/GenericTouchable.js +4 -1
  27. package/lib/commonjs/components/touchables/GenericTouchable.js.map +1 -1
  28. package/lib/commonjs/fabric/RNGestureHandlerButtonNativeComponent.js.map +1 -1
  29. package/lib/commonjs/handlers/ForceTouchGestureHandler.js +2 -1
  30. package/lib/commonjs/handlers/ForceTouchGestureHandler.js.map +1 -1
  31. package/lib/commonjs/handlers/PanGestureHandler.js +1 -1
  32. package/lib/commonjs/handlers/PanGestureHandler.js.map +1 -1
  33. package/lib/commonjs/handlers/PressabilityDebugView.js +14 -0
  34. package/lib/commonjs/handlers/PressabilityDebugView.js.map +1 -0
  35. package/lib/commonjs/handlers/PressabilityDebugView.web.js +12 -0
  36. package/lib/commonjs/handlers/PressabilityDebugView.web.js.map +1 -0
  37. package/lib/commonjs/handlers/createHandler.js +25 -11
  38. package/lib/commonjs/handlers/createHandler.js.map +1 -1
  39. package/lib/commonjs/handlers/gestureHandlerCommon.js.map +1 -1
  40. package/lib/commonjs/handlers/gestures/GestureDetector.js +83 -63
  41. package/lib/commonjs/handlers/gestures/GestureDetector.js.map +1 -1
  42. package/lib/commonjs/handlers/gestures/gesture.js +13 -2
  43. package/lib/commonjs/handlers/gestures/gesture.js.map +1 -1
  44. package/lib/commonjs/handlers/gestures/gestureStateManager.js +13 -9
  45. package/lib/commonjs/handlers/gestures/gestureStateManager.js.map +1 -1
  46. package/lib/commonjs/handlers/gestures/panGesture.js +5 -0
  47. package/lib/commonjs/handlers/gestures/panGesture.js.map +1 -1
  48. package/lib/commonjs/mocks.js +2 -0
  49. package/lib/commonjs/mocks.js.map +1 -1
  50. package/lib/commonjs/utils.js +6 -3
  51. package/lib/commonjs/utils.js.map +1 -1
  52. package/lib/commonjs/web/utils.js.map +1 -1
  53. package/lib/module/RNGestureHandlerModule.macos.js +57 -0
  54. package/lib/module/RNGestureHandlerModule.macos.js.map +1 -0
  55. package/lib/module/components/DrawerLayout.js +38 -11
  56. package/lib/module/components/DrawerLayout.js.map +1 -1
  57. package/lib/module/components/GestureButtons.js.map +1 -1
  58. package/lib/module/components/touchables/GenericTouchable.js +4 -1
  59. package/lib/module/components/touchables/GenericTouchable.js.map +1 -1
  60. package/lib/module/fabric/RNGestureHandlerButtonNativeComponent.js.map +1 -1
  61. package/lib/module/handlers/ForceTouchGestureHandler.js +1 -1
  62. package/lib/module/handlers/ForceTouchGestureHandler.js.map +1 -1
  63. package/lib/module/handlers/PanGestureHandler.js +1 -1
  64. package/lib/module/handlers/PanGestureHandler.js.map +1 -1
  65. package/lib/module/handlers/PressabilityDebugView.js +3 -0
  66. package/lib/module/handlers/PressabilityDebugView.js.map +1 -0
  67. package/lib/module/handlers/PressabilityDebugView.web.js +5 -0
  68. package/lib/module/handlers/PressabilityDebugView.web.js.map +1 -0
  69. package/lib/module/handlers/createHandler.js +26 -12
  70. package/lib/module/handlers/createHandler.js.map +1 -1
  71. package/lib/module/handlers/gestureHandlerCommon.js.map +1 -1
  72. package/lib/module/handlers/gestures/GestureDetector.js +83 -63
  73. package/lib/module/handlers/gestures/GestureDetector.js.map +1 -1
  74. package/lib/module/handlers/gestures/gesture.js +13 -2
  75. package/lib/module/handlers/gestures/gesture.js.map +1 -1
  76. package/lib/module/handlers/gestures/gestureStateManager.js +13 -9
  77. package/lib/module/handlers/gestures/gestureStateManager.js.map +1 -1
  78. package/lib/module/handlers/gestures/panGesture.js +5 -0
  79. package/lib/module/handlers/gestures/panGesture.js.map +1 -1
  80. package/lib/module/mocks.js +2 -0
  81. package/lib/module/mocks.js.map +1 -1
  82. package/lib/module/utils.js +2 -1
  83. package/lib/module/utils.js.map +1 -1
  84. package/lib/module/web/utils.js.map +1 -1
  85. package/lib/typescript/RNGestureHandlerModule.macos.d.ts +34 -0
  86. package/lib/typescript/RNGestureHandlerModule.web.d.ts +1 -1
  87. package/lib/typescript/components/DrawerLayout.d.ts +3 -0
  88. package/lib/typescript/components/GestureButtons.d.ts +6 -0
  89. package/lib/typescript/fabric/RNGestureHandlerButtonNativeComponent.d.ts +1 -0
  90. package/lib/typescript/handlers/ForceTouchGestureHandler.d.ts +2 -2
  91. package/lib/typescript/handlers/PanGestureHandler.d.ts +2 -1
  92. package/lib/typescript/handlers/PressabilityDebugView.d.ts +1 -0
  93. package/lib/typescript/handlers/PressabilityDebugView.web.d.ts +1 -0
  94. package/lib/typescript/handlers/gestureHandlerCommon.d.ts +1 -0
  95. package/lib/typescript/handlers/gestures/GestureDetector.d.ts +2 -1
  96. package/lib/typescript/handlers/gestures/gesture.d.ts +3 -0
  97. package/lib/typescript/handlers/gestures/panGesture.d.ts +1 -0
  98. package/lib/typescript/mocks.d.ts +1 -0
  99. package/lib/typescript/web/NodeManager.d.ts +2 -2
  100. package/package.json +1 -1
  101. package/src/RNGestureHandlerModule.macos.ts +62 -0
  102. package/src/components/DrawerLayout.tsx +34 -10
  103. package/src/components/GestureButtons.tsx +7 -0
  104. package/src/components/touchables/GenericTouchable.tsx +1 -0
  105. package/src/fabric/RNGestureHandlerButtonNativeComponent.ts +1 -0
  106. package/src/handlers/ForceTouchGestureHandler.ts +3 -2
  107. package/src/handlers/PanGestureHandler.ts +2 -0
  108. package/src/handlers/PressabilityDebugView.tsx +2 -0
  109. package/src/handlers/PressabilityDebugView.web.tsx +4 -0
  110. package/src/handlers/{createHandler.ts → createHandler.tsx} +32 -17
  111. package/src/handlers/gestureHandlerCommon.ts +2 -0
  112. package/src/handlers/gestures/GestureDetector.tsx +107 -81
  113. package/src/handlers/gestures/gesture.ts +16 -0
  114. package/src/handlers/gestures/gestureStateManager.ts +13 -8
  115. package/src/handlers/gestures/panGesture.ts +5 -0
  116. package/src/mocks.ts +2 -0
  117. package/src/utils.ts +3 -1
  118. package/src/web/utils.ts +1 -1
  119. package/ios/RNGestureHandler.xcodeproj/project.xcworkspace/xcuserdata/jakubpiasecki.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  120. package/ios/RNGestureHandler.xcodeproj/xcuserdata/jakubpiasecki.xcuserdatad/xcschemes/xcschememanagement.plist +0 -19
package/README.md CHANGED
@@ -24,7 +24,7 @@ Check out our dedicated documentation page for info about this library, API refe
24
24
  If you want to play with the API but don't feel like trying it on a real app, you can run the example project. Clone the repo, go to the `example` folder and run:
25
25
 
26
26
  ```bash
27
- yarn install
27
+ yarn install
28
28
  ```
29
29
 
30
30
  If you are running on ios, run `pod install` in the ios folder
@@ -44,7 +44,8 @@ You will need to have an Android or iOS device or emulator connected as well as
44
44
  | <1.1.0 | 0.50.0+ |
45
45
 
46
46
  It may be possible to use newer versions of react-native-gesture-handler on React Native with version <= 0.59 by reverse Jetifying.
47
- Read more on that here https://github.com/mikehardy/jetifier#to-reverse-jetify--convert-node_modules-dependencies-to-support-libraries
47
+ Read more on that here <https://github.com/mikehardy/jetifier#to-reverse-jetify--convert-node_modules-dependencies-to-support-libraries>
48
+
48
49
  ## License
49
50
 
50
51
  Gesture handler library is licensed under [The MIT License](LICENSE).
@@ -1,4 +1,5 @@
1
1
  import groovy.json.JsonSlurper
2
+ import java.nio.file.Paths
2
3
 
3
4
  buildscript {
4
5
  def kotlin_version = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : project.properties['RNGH_kotlinVersion']
@@ -20,6 +21,20 @@ def isNewArchitectureEnabled() {
20
21
  return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
21
22
  }
22
23
 
24
+ def findNodeModulePath(baseDir, packageName) {
25
+ def basePath = baseDir.toPath().normalize()
26
+ // Node's module resolution algorithm searches up to the root directory,
27
+ // after which the base path will be null
28
+ while (basePath) {
29
+ def candidatePath = Paths.get(basePath.toString(), "node_modules", packageName)
30
+ if (candidatePath.toFile().exists()) {
31
+ return candidatePath.toString()
32
+ }
33
+ basePath = basePath.getParent()
34
+ }
35
+ return null
36
+ }
37
+
23
38
  if (isNewArchitectureEnabled()) {
24
39
  apply plugin: 'com.facebook.react'
25
40
  }
@@ -51,6 +66,15 @@ repositories {
51
66
  android {
52
67
  compileSdkVersion safeExtGet("compileSdkVersion", 28)
53
68
 
69
+ // Used to override the NDK path/version on internal CI or by allowing
70
+ // users to customize the NDK path/version from their root project (e.g. for M1 support)
71
+ if (rootProject.hasProperty("ndkPath")) {
72
+ ndkPath rootProject.ext.ndkPath
73
+ }
74
+ if (rootProject.hasProperty("ndkVersion")) {
75
+ ndkVersion rootProject.ext.ndkVersion
76
+ }
77
+
54
78
  defaultConfig {
55
79
  minSdkVersion safeExtGet('minSdkVersion', 16)
56
80
  targetSdkVersion safeExtGet('targetSdkVersion', 28)
@@ -66,8 +90,8 @@ android {
66
90
  "NDK_TOOLCHAIN_VERSION=clang",
67
91
  "GENERATED_SRC_DIR=${appProject.buildDir}/generated/source",
68
92
  "PROJECT_BUILD_DIR=${appProject.buildDir}",
69
- "REACT_ANDROID_DIR=${appProject.rootDir}/../node_modules/react-native/ReactAndroid",
70
- "REACT_ANDROID_BUILD_DIR=${appProject.rootDir}/../node_modules/react-native/ReactAndroid/build"
93
+ "REACT_ANDROID_DIR=${findNodeModulePath(appProject.rootDir, "react-native") ?: "../node_modules/react-native/"}/ReactAndroid",
94
+ "REACT_ANDROID_BUILD_DIR=${findNodeModulePath(appProject.rootDir, "react-native") ?: "../node_modules/react-native/"}/ReactAndroid/build"
71
95
  cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
72
96
  cppFlags "-std=c++17"
73
97
  targets "rngesturehandler_modules"
@@ -148,9 +172,9 @@ dependencies {
148
172
 
149
173
  if (isNewArchitectureEnabled()) {
150
174
  react {
151
- reactRoot = rootProject.file("../node_modules/react-native/")
175
+ reactNativeDir = rootProject.file(findNodeModulePath(rootProject.rootDir, "react-native") ?: "../node_modules/react-native/")
152
176
  jsRootDir = file("../src/fabric/")
153
- codegenDir = rootProject.file("../node_modules/react-native-codegen/")
177
+ codegenDir = rootProject.file(findNodeModulePath(rootProject.rootDir, "react-native-codegen") ?: "../node_modules/react-native-codegen/")
154
178
  libraryName = "rngesturehandler"
155
179
  codegenJavaPackageName = "com.swmansion.gesturehandler"
156
180
  }
@@ -172,8 +172,12 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
172
172
  windowOffset[0] = 0
173
173
  windowOffset[1] = 0
174
174
  }
175
+
176
+ onPrepare()
175
177
  }
176
178
 
179
+ protected open fun onPrepare() {}
180
+
177
181
  private fun getWindow(context: Context?): Window? {
178
182
  if (context == null) return null
179
183
  if (context is Activity) return context.window
@@ -253,9 +257,9 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
253
257
  }
254
258
  initPointerProps(trackedPointersIDsCount)
255
259
  var count = 0
256
- val oldX = event.x
257
- val oldY = event.y
258
- event.setLocation(event.rawX, event.rawY)
260
+ val deltaX = event.rawX - event.x
261
+ val deltaY = event.rawY - event.y
262
+ event.offsetLocation(deltaX, deltaY)
259
263
  var index = 0
260
264
  val size = event.pointerCount
261
265
  while (index < size) {
@@ -298,8 +302,8 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
298
302
  } catch (e: IllegalArgumentException) {
299
303
  throw AdaptEventException(this, event, e)
300
304
  }
301
- event.setLocation(oldX, oldY)
302
- result.setLocation(oldX, oldY)
305
+ event.offsetLocation(-deltaX, -deltaY)
306
+ result.offsetLocation(-deltaX, -deltaY)
303
307
  return result
304
308
  }
305
309
 
@@ -475,7 +475,12 @@ class GestureHandlerOrchestrator(
475
475
  PointerEventsConfig.BOX_NONE -> {
476
476
  // This view can't be the target, but its children might
477
477
  if (view is ViewGroup) {
478
- extractGestureHandlers(view, coords, pointerId)
478
+ extractGestureHandlers(view, coords, pointerId).also { found ->
479
+ // A child view is handling touch, also extract handlers attached to this view
480
+ if (found) {
481
+ recordViewHandlersForPointer(view, coords, pointerId)
482
+ }
483
+ }
479
484
  } else false
480
485
  }
481
486
  PointerEventsConfig.AUTO -> {
@@ -3,13 +3,16 @@ package com.swmansion.gesturehandler
3
3
  import android.os.SystemClock
4
4
  import android.view.MotionEvent
5
5
  import android.view.View
6
+ import android.view.ViewConfiguration
6
7
  import android.view.ViewGroup
7
- import com.swmansion.gesturehandler.react.RNGestureHandlerButtonViewManager
8
+ import com.facebook.react.views.textinput.ReactEditText
8
9
 
9
10
  class NativeViewGestureHandler : GestureHandler<NativeViewGestureHandler>() {
10
11
  private var shouldActivateOnStart = false
11
12
  private var disallowInterruption = false
12
13
 
14
+ private var hook: NativeViewGestureHandlerHook = defaultHook
15
+
13
16
  init {
14
17
  setShouldCancelWhenOutside(true)
15
18
  }
@@ -34,13 +37,17 @@ class NativeViewGestureHandler : GestureHandler<NativeViewGestureHandler>() {
34
37
  }
35
38
 
36
39
  override fun shouldRecognizeSimultaneously(handler: GestureHandler<*>): Boolean {
40
+ // if the gesture is marked by user as simultaneous with other or the hook return true
41
+ if (super.shouldRecognizeSimultaneously(handler) || hook.shouldRecognizeSimultaneously(handler)) {
42
+ return true
43
+ }
44
+
37
45
  if (handler is NativeViewGestureHandler) {
38
46
  // Special case when the peer handler is also an instance of NativeViewGestureHandler:
39
47
  // For the `disallowInterruption` to work correctly we need to check the property when
40
48
  // accessed as a peer, because simultaneous recognizers can be set on either side of the
41
49
  // connection.
42
- val nativeWrapper = handler
43
- if (nativeWrapper.state == STATE_ACTIVE && nativeWrapper.disallowInterruption) {
50
+ if (handler.state == STATE_ACTIVE && handler.disallowInterruption) {
44
51
  // other handler is active and it disallows interruption, we don't want to get into its way
45
52
  return false
46
53
  }
@@ -52,7 +59,7 @@ class NativeViewGestureHandler : GestureHandler<NativeViewGestureHandler>() {
52
59
  // as it means the other handler has turned active and returning `true` would prevent it from
53
60
  // interrupting the current handler
54
61
  false
55
- } else state == STATE_ACTIVE && canBeInterrupted
62
+ } else state == STATE_ACTIVE && canBeInterrupted && (!hook.shouldCancelRootViewGestureHandlerIfNecessary() || handler.tag > 0)
56
63
  // otherwise we can only return `true` if already in an active state
57
64
  }
58
65
 
@@ -60,19 +67,10 @@ class NativeViewGestureHandler : GestureHandler<NativeViewGestureHandler>() {
60
67
  return !disallowInterruption
61
68
  }
62
69
 
63
- private fun canStart(): Boolean {
64
- val view = view
65
- if (view is StateChangeHook) {
66
- return view.canStart()
67
- }
68
-
69
- return true
70
- }
71
-
72
- private fun afterGestureEnd() {
73
- val view = view
74
- if (view is StateChangeHook) {
75
- view.afterGestureEnd()
70
+ override fun onPrepare() {
71
+ when (val view = view) {
72
+ is NativeViewGestureHandlerHook -> this.hook = view
73
+ is ReactEditText -> this.hook = EditTextHook(this, view)
76
74
  }
77
75
  }
78
76
 
@@ -84,7 +82,7 @@ class NativeViewGestureHandler : GestureHandler<NativeViewGestureHandler>() {
84
82
  activate()
85
83
  }
86
84
  end()
87
- afterGestureEnd()
85
+ hook.afterGestureEnd(event)
88
86
  } else if (state == STATE_UNDETERMINED || state == STATE_BEGAN) {
89
87
  when {
90
88
  shouldActivateOnStart -> {
@@ -96,8 +94,11 @@ class NativeViewGestureHandler : GestureHandler<NativeViewGestureHandler>() {
96
94
  view.onTouchEvent(event)
97
95
  activate()
98
96
  }
97
+ hook.wantsToHandleEventBeforeActivation() -> {
98
+ hook.handleEventBeforeActivation(event)
99
+ }
99
100
  state != STATE_BEGAN -> {
100
- if (canStart()) {
101
+ if (hook.canBegin()) {
101
102
  begin()
102
103
  } else {
103
104
  cancel()
@@ -117,13 +118,93 @@ class NativeViewGestureHandler : GestureHandler<NativeViewGestureHandler>() {
117
118
  view!!.onTouchEvent(event)
118
119
  }
119
120
 
121
+ override fun onReset() {
122
+ this.hook = defaultHook
123
+ }
124
+
120
125
  companion object {
121
126
  private fun tryIntercept(view: View, event: MotionEvent) =
122
127
  view is ViewGroup && view.onInterceptTouchEvent(event)
128
+
129
+ private val defaultHook = object : NativeViewGestureHandlerHook {}
123
130
  }
124
131
 
125
- interface StateChangeHook {
126
- fun canStart(): Boolean
127
- fun afterGestureEnd()
132
+ interface NativeViewGestureHandlerHook {
133
+ /**
134
+ * Called when gesture is in the UNDETERMINED state, shouldActivateOnStart is set to false,
135
+ * and both tryIntercept and wantsToHandleEventBeforeActivation returned false.
136
+ *
137
+ * @return Boolean value signalling whether the handler can transition to the BEGAN state. If false
138
+ * the gesture will be cancelled.
139
+ */
140
+ fun canBegin() = true
141
+
142
+ /**
143
+ * Called after the gesture transitions to the END state.
144
+ */
145
+ fun afterGestureEnd(event: MotionEvent) = Unit
146
+
147
+ /**
148
+ * @return Boolean value signalling whether the gesture can be recognized simultaneously with
149
+ * other (handler). Returning false doesn't necessarily prevent it from happening.
150
+ */
151
+ fun shouldRecognizeSimultaneously(handler: GestureHandler<*>) = false
152
+
153
+ /**
154
+ * shouldActivateOnStart and tryIntercept have priority over this method
155
+ *
156
+ * @return Boolean value signalling if the hook wants to handle events passed to the handler
157
+ * before it activates (after that the events are passed to the underlying view).
158
+ */
159
+ fun wantsToHandleEventBeforeActivation() = false
160
+
161
+ /**
162
+ * Will be called with events if wantsToHandleEventBeforeActivation returns true.
163
+ */
164
+ fun handleEventBeforeActivation(event: MotionEvent) = Unit
165
+
166
+ /**
167
+ * @return Boolean value indicating whether the RootViewGestureHandler should be cancelled
168
+ * by this one.
169
+ */
170
+ fun shouldCancelRootViewGestureHandlerIfNecessary() = false
171
+ }
172
+
173
+ private class EditTextHook(
174
+ private val handler: NativeViewGestureHandler,
175
+ private val editText: ReactEditText
176
+ ) : NativeViewGestureHandlerHook {
177
+ private var startX = 0f
178
+ private var startY = 0f
179
+ private var touchSlopSquared: Int
180
+
181
+ init {
182
+ val vc = ViewConfiguration.get(editText.context)
183
+ touchSlopSquared = vc.scaledTouchSlop * vc.scaledTouchSlop
184
+ }
185
+
186
+ override fun afterGestureEnd(event: MotionEvent) {
187
+ if ((event.x - startX) * (event.x - startX) + (event.y - startY) * (event.y - startY) < touchSlopSquared) {
188
+ editText.requestFocusFromJS()
189
+ }
190
+ }
191
+
192
+ // recognize alongside every handler besides RootViewGestureHandler, which is a private inner class
193
+ // of RNGestureHandlerRootHelper so no explicit type checks, but its tag is always negative
194
+ // also if other handler is NativeViewGestureHandler then don't override the default implementation
195
+ override fun shouldRecognizeSimultaneously(handler: GestureHandler<*>) =
196
+ handler.tag > 0 && handler !is NativeViewGestureHandler
197
+
198
+ override fun wantsToHandleEventBeforeActivation() = true
199
+
200
+ override fun handleEventBeforeActivation(event: MotionEvent) {
201
+ handler.activate()
202
+ editText.onTouchEvent(event)
203
+
204
+ startX = event.x
205
+ startY = event.y
206
+ }
207
+
208
+ override fun shouldCancelRootViewGestureHandlerIfNecessary() = true
128
209
  }
129
210
  }
@@ -1,6 +1,7 @@
1
1
  package com.swmansion.gesturehandler
2
2
 
3
3
  import android.content.Context
4
+ import android.os.Handler
4
5
  import android.view.MotionEvent
5
6
  import android.view.VelocityTracker
6
7
  import android.view.ViewConfiguration
@@ -40,6 +41,9 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
40
41
  private var lastY = 0f
41
42
  private var velocityTracker: VelocityTracker? = null
42
43
  private var averageTouches = false
44
+ private var activateAfterLongPress = DEFAULT_ACTIVATE_AFTER_LONG_PRESS
45
+ private val activateDelayed = Runnable { activate() }
46
+ private var handler: Handler? = null
43
47
 
44
48
  /**
45
49
  * On Android when there are multiple pointers on the screen pan gestures most often just consider
@@ -54,7 +58,7 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
54
58
  * position of all the fingers will remain still while doing a rotation gesture.
55
59
  */
56
60
  init {
57
- val vc = ViewConfiguration.get(context)
61
+ val vc = ViewConfiguration.get(context!!)
58
62
  val touchSlop = vc.scaledTouchSlop
59
63
  defaultMinDistSq = (touchSlop * touchSlop).toFloat()
60
64
  minDistSq = defaultMinDistSq
@@ -76,6 +80,7 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
76
80
  minDistSq = defaultMinDistSq
77
81
  minPointers = DEFAULT_MIN_POINTERS
78
82
  maxPointers = DEFAULT_MAX_POINTERS
83
+ activateAfterLongPress = DEFAULT_ACTIVATE_AFTER_LONG_PRESS
79
84
  averageTouches = false
80
85
  }
81
86
 
@@ -127,6 +132,10 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
127
132
  this.averageTouches = averageTouches
128
133
  }
129
134
 
135
+ fun setActivateAfterLongPress(time: Long) = apply {
136
+ this.activateAfterLongPress = time
137
+ }
138
+
130
139
  /**
131
140
  * @param minVelocity in pixels per second
132
141
  */
@@ -177,13 +186,18 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
177
186
 
178
187
  private fun shouldFail(): Boolean {
179
188
  val dx = lastX - startX + offsetX
189
+ val dy = lastY - startY + offsetY
190
+
191
+ if (activateAfterLongPress > 0 && dx * dx + dy * dy > defaultMinDistSq) {
192
+ handler?.removeCallbacksAndMessages(null)
193
+ return true
194
+ }
180
195
  if (failOffsetXStart != MAX_VALUE_IGNORE && dx < failOffsetXStart) {
181
196
  return true
182
197
  }
183
198
  if (failOffsetXEnd != MIN_VALUE_IGNORE && dx > failOffsetXEnd) {
184
199
  return true
185
200
  }
186
- val dy = lastY - startY + offsetY
187
201
  if (failOffsetYStart != MAX_VALUE_IGNORE && dy < failOffsetYStart) {
188
202
  return true
189
203
  }
@@ -216,6 +230,13 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
216
230
  velocityTracker = VelocityTracker.obtain()
217
231
  addVelocityMovement(velocityTracker, event)
218
232
  begin()
233
+
234
+ if (activateAfterLongPress > 0) {
235
+ if (handler == null) {
236
+ handler = Handler()
237
+ }
238
+ handler!!.postDelayed(activateDelayed, activateAfterLongPress)
239
+ }
219
240
  } else if (velocityTracker != null) {
220
241
  addVelocityMovement(velocityTracker, event)
221
242
  velocityTracker!!.computeCurrentVelocity(1000)
@@ -257,7 +278,12 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
257
278
  super.activate(force)
258
279
  }
259
280
 
281
+ override fun onCancel() {
282
+ handler?.removeCallbacksAndMessages(null)
283
+ }
284
+
260
285
  override fun onReset() {
286
+ handler?.removeCallbacksAndMessages(null)
261
287
  velocityTracker?.let {
262
288
  it.recycle()
263
289
  velocityTracker = null
@@ -274,6 +300,7 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
274
300
  private const val MAX_VALUE_IGNORE = Float.MIN_VALUE
275
301
  private const val DEFAULT_MIN_POINTERS = 1
276
302
  private const val DEFAULT_MAX_POINTERS = 10
303
+ private const val DEFAULT_ACTIVATE_AFTER_LONG_PRESS = 0L
277
304
 
278
305
  /**
279
306
  * This method adds movement to {@class VelocityTracker} first resetting offset of the event so