react-native-gesture-handler 2.6.2 → 2.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. package/android/build.gradle +0 -8
  2. package/android/gradle.properties +1 -1
  3. package/android/lib/src/main/java/com/swmansion/gesturehandler/FlingGestureHandler.kt +7 -7
  4. package/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandler.kt +46 -26
  5. package/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerOrchestrator.kt +76 -29
  6. package/android/lib/src/main/java/com/swmansion/gesturehandler/GestureUtils.kt +4 -6
  7. package/android/lib/src/main/java/com/swmansion/gesturehandler/LongPressGestureHandler.kt +6 -6
  8. package/android/lib/src/main/java/com/swmansion/gesturehandler/ManualGestureHandler.kt +1 -1
  9. package/android/lib/src/main/java/com/swmansion/gesturehandler/NativeViewGestureHandler.kt +1 -1
  10. package/android/lib/src/main/java/com/swmansion/gesturehandler/PanGestureHandler.kt +11 -11
  11. package/android/lib/src/main/java/com/swmansion/gesturehandler/PinchGestureHandler.kt +17 -9
  12. package/android/lib/src/main/java/com/swmansion/gesturehandler/RotationGestureHandler.kt +15 -8
  13. package/android/lib/src/main/java/com/swmansion/gesturehandler/TapGestureHandler.kt +10 -10
  14. package/android/noreanimated/src/main/java/com/swmansion/gesturehandler/ReanimatedEventDispatcher.kt +1 -1
  15. package/android/reanimated/src/main/java/com/swmansion/gesturehandler/ReanimatedEventDispatcher.kt +1 -1
  16. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +31 -12
  17. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt +2 -2
  18. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt +1 -1
  19. package/ios/RNGestureHandlerButtonComponentView.mm +4 -4
  20. package/lib/commonjs/handlers/gestures/GestureDetector.js +9 -2
  21. package/lib/commonjs/handlers/gestures/GestureDetector.js.map +1 -1
  22. package/lib/commonjs/handlers/gestures/gestureComposition.js +15 -4
  23. package/lib/commonjs/handlers/gestures/gestureComposition.js.map +1 -1
  24. package/lib/commonjs/web/handlers/FlingGestureHandler.js +18 -14
  25. package/lib/commonjs/web/handlers/FlingGestureHandler.js.map +1 -1
  26. package/lib/commonjs/web/handlers/GestureHandler.js +8 -4
  27. package/lib/commonjs/web/handlers/GestureHandler.js.map +1 -1
  28. package/lib/commonjs/web/handlers/LongPressGestureHandler.js +2 -0
  29. package/lib/commonjs/web/handlers/LongPressGestureHandler.js.map +1 -1
  30. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js +1 -4
  31. package/lib/commonjs/web/handlers/NativeViewGestureHandler.js.map +1 -1
  32. package/lib/commonjs/web/handlers/PanGestureHandler.js +2 -2
  33. package/lib/commonjs/web/handlers/PanGestureHandler.js.map +1 -1
  34. package/lib/commonjs/web/tools/PointerTracker.js +2 -2
  35. package/lib/commonjs/web/tools/PointerTracker.js.map +1 -1
  36. package/lib/module/handlers/gestures/GestureDetector.js +9 -2
  37. package/lib/module/handlers/gestures/GestureDetector.js.map +1 -1
  38. package/lib/module/handlers/gestures/gestureComposition.js +15 -4
  39. package/lib/module/handlers/gestures/gestureComposition.js.map +1 -1
  40. package/lib/module/web/handlers/FlingGestureHandler.js +18 -14
  41. package/lib/module/web/handlers/FlingGestureHandler.js.map +1 -1
  42. package/lib/module/web/handlers/GestureHandler.js +8 -3
  43. package/lib/module/web/handlers/GestureHandler.js.map +1 -1
  44. package/lib/module/web/handlers/LongPressGestureHandler.js +2 -0
  45. package/lib/module/web/handlers/LongPressGestureHandler.js.map +1 -1
  46. package/lib/module/web/handlers/NativeViewGestureHandler.js +1 -4
  47. package/lib/module/web/handlers/NativeViewGestureHandler.js.map +1 -1
  48. package/lib/module/web/handlers/PanGestureHandler.js +2 -2
  49. package/lib/module/web/handlers/PanGestureHandler.js.map +1 -1
  50. package/lib/module/web/tools/PointerTracker.js +2 -2
  51. package/lib/module/web/tools/PointerTracker.js.map +1 -1
  52. package/lib/typescript/web/handlers/FlingGestureHandler.d.ts +1 -0
  53. package/lib/typescript/web/handlers/GestureHandler.d.ts +1 -0
  54. package/package.json +4 -8
  55. package/src/handlers/gestures/GestureDetector.tsx +10 -3
  56. package/src/handlers/gestures/gestureComposition.ts +19 -6
  57. package/src/web/handlers/FlingGestureHandler.ts +26 -17
  58. package/src/web/handlers/GestureHandler.ts +13 -6
  59. package/src/web/handlers/LongPressGestureHandler.ts +2 -0
  60. package/src/web/handlers/NativeViewGestureHandler.ts +1 -4
  61. package/src/web/handlers/PanGestureHandler.ts +2 -2
  62. package/src/web/tools/PointerTracker.ts +2 -2
  63. package/ios/RNGestureHandler.xcodeproj/project.xcworkspace/xcuserdata/jakubpiasecki.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  64. package/ios/RNGestureHandler.xcodeproj/xcuserdata/jakubpiasecki.xcuserdatad/xcschemes/xcschememanagement.plist +0 -19
@@ -212,14 +212,6 @@ dependencies {
212
212
  }
213
213
 
214
214
  if (isNewArchitectureEnabled()) {
215
- react {
216
- reactNativeDir = rootProject.file(findNodeModulePath(rootProject.rootDir, "react-native") ?: "../node_modules/react-native/")
217
- jsRootDir = file("../src/fabric/")
218
- codegenDir = rootProject.file(findNodeModulePath(rootProject.rootDir, "react-native-codegen") ?: "../node_modules/react-native-codegen/")
219
- libraryName = "rngesturehandler"
220
- codegenJavaPackageName = "com.swmansion.gesturehandler"
221
- }
222
-
223
215
  // Resolves "LOCAL_SRC_FILES points to a missing file, Check that libfb.so exists or that its path is correct".
224
216
  tasks.whenTaskAdded { task ->
225
217
  if (task.name.contains("configureCMakeDebug")) {
@@ -16,4 +16,4 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryErro
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=1.5.20
19
+ RNGH_kotlinVersion=1.6.21
@@ -63,19 +63,19 @@ class FlingGestureHandler : GestureHandler<FlingGestureHandler>() {
63
63
  }
64
64
  }
65
65
 
66
- override fun onHandle(event: MotionEvent) {
66
+ override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) {
67
67
  val state = state
68
68
  if (state == STATE_UNDETERMINED) {
69
- startFling(event)
69
+ startFling(sourceEvent)
70
70
  }
71
71
  if (state == STATE_BEGAN) {
72
- tryEndFling(event)
73
- if (event.pointerCount > maxNumberOfPointersSimultaneously) {
74
- maxNumberOfPointersSimultaneously = event.pointerCount
72
+ tryEndFling(sourceEvent)
73
+ if (sourceEvent.pointerCount > maxNumberOfPointersSimultaneously) {
74
+ maxNumberOfPointersSimultaneously = sourceEvent.pointerCount
75
75
  }
76
- val action = event.actionMasked
76
+ val action = sourceEvent.actionMasked
77
77
  if (action == MotionEvent.ACTION_UP) {
78
- endFling(event)
78
+ endFling(sourceEvent)
79
79
  }
80
80
  }
81
81
  }
@@ -3,6 +3,7 @@ package com.swmansion.gesturehandler
3
3
  import android.app.Activity
4
4
  import android.content.Context
5
5
  import android.content.ContextWrapper
6
+ import android.graphics.PointF
6
7
  import android.graphics.Rect
7
8
  import android.view.MotionEvent
8
9
  import android.view.MotionEvent.PointerCoords
@@ -325,7 +326,7 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
325
326
  while handling event: $event
326
327
  """.trimIndent(), e) {}
327
328
 
328
- fun handle(origEvent: MotionEvent) {
329
+ fun handle(transformedEvent: MotionEvent, sourceEvent: MotionEvent) {
329
330
  if (!isEnabled
330
331
  || state == STATE_CANCELLED
331
332
  || state == STATE_FAILED
@@ -335,20 +336,20 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
335
336
  }
336
337
 
337
338
  // a workaround for https://github.com/software-mansion/react-native-gesture-handler/issues/1188
338
- val event = if (BuildConfig.DEBUG) {
339
- adaptEvent(origEvent)
339
+ val (adaptedTransformedEvent, adaptedSourceEvent) = if (BuildConfig.DEBUG) {
340
+ arrayOf(adaptEvent(transformedEvent), adaptEvent(sourceEvent))
340
341
  } else {
341
342
  try {
342
- adaptEvent(origEvent)
343
+ arrayOf(adaptEvent(transformedEvent), adaptEvent(sourceEvent))
343
344
  } catch (e: AdaptEventException) {
344
345
  fail()
345
346
  return
346
347
  }
347
348
  }
348
349
 
349
- x = event.x
350
- y = event.y
351
- numberOfPointers = event.pointerCount
350
+ x = adaptedTransformedEvent.x
351
+ y = adaptedTransformedEvent.y
352
+ numberOfPointers = adaptedTransformedEvent.pointerCount
352
353
  isWithinBounds = isWithinBounds(view, x, y)
353
354
  if (shouldCancelWhenOutside && !isWithinBounds) {
354
355
  if (state == STATE_ACTIVE) {
@@ -358,13 +359,16 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
358
359
  }
359
360
  return
360
361
  }
361
- lastAbsolutePositionX = GestureUtils.getLastPointerX(event, true)
362
- lastAbsolutePositionY = GestureUtils.getLastPointerY(event, true)
363
- lastEventOffsetX = event.rawX - event.x
364
- lastEventOffsetY = event.rawY - event.y
365
- onHandle(event)
366
- if (event != origEvent) {
367
- event.recycle()
362
+ lastAbsolutePositionX = GestureUtils.getLastPointerX(adaptedTransformedEvent, true)
363
+ lastAbsolutePositionY = GestureUtils.getLastPointerY(adaptedTransformedEvent, true)
364
+ lastEventOffsetX = adaptedTransformedEvent.rawX - adaptedTransformedEvent.x
365
+ lastEventOffsetY = adaptedTransformedEvent.rawY - adaptedTransformedEvent.y
366
+ onHandle(adaptedTransformedEvent, adaptedSourceEvent)
367
+ if (adaptedTransformedEvent != transformedEvent) {
368
+ adaptedTransformedEvent.recycle()
369
+ }
370
+ if (adaptedSourceEvent != sourceEvent) {
371
+ adaptedSourceEvent.recycle()
368
372
  }
369
373
  }
370
374
 
@@ -585,11 +589,11 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
585
589
  var top = 0f
586
590
  var right = view!!.width.toFloat()
587
591
  var bottom = view.height.toFloat()
588
- if (hitSlop != null) {
589
- val padLeft = hitSlop!![HIT_SLOP_LEFT_IDX]
590
- val padTop = hitSlop!![HIT_SLOP_TOP_IDX]
591
- val padRight = hitSlop!![HIT_SLOP_RIGHT_IDX]
592
- val padBottom = hitSlop!![HIT_SLOP_BOTTOM_IDX]
592
+ hitSlop?.let { hitSlop ->
593
+ val padLeft = hitSlop[HIT_SLOP_LEFT_IDX]
594
+ val padTop = hitSlop[HIT_SLOP_TOP_IDX]
595
+ val padRight = hitSlop[HIT_SLOP_RIGHT_IDX]
596
+ val padBottom = hitSlop[HIT_SLOP_BOTTOM_IDX]
593
597
  if (hitSlopSet(padLeft)) {
594
598
  left -= padLeft
595
599
  }
@@ -602,8 +606,8 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
602
606
  if (hitSlopSet(padBottom)) {
603
607
  bottom += padBottom
604
608
  }
605
- val width = hitSlop!![HIT_SLOP_WIDTH_IDX]
606
- val height = hitSlop!![HIT_SLOP_HEIGHT_IDX]
609
+ val width = hitSlop[HIT_SLOP_WIDTH_IDX]
610
+ val height = hitSlop[HIT_SLOP_HEIGHT_IDX]
607
611
  if (hitSlopSet(width)) {
608
612
  if (!hitSlopSet(padLeft)) {
609
613
  left = right - width
@@ -659,13 +663,29 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
659
663
  // if the handler is waiting for failure of other one)
660
664
  open fun resetProgress() {}
661
665
 
662
- protected open fun onHandle(event: MotionEvent) {
666
+ protected open fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) {
663
667
  moveToState(STATE_FAILED)
664
668
  }
665
669
 
666
670
  protected open fun onStateChange(newState: Int, previousState: Int) {}
667
671
  protected open fun onReset() {}
668
672
  protected open fun onCancel() {}
673
+
674
+ /**
675
+ * Transforms a point in the coordinate space of the wrapperView (GestureHandlerRootView) to
676
+ * coordinate space of the view the gesture is attached to.
677
+ *
678
+ * If the gesture handler is not currently attached to a view, it will return (NaN, NaN).
679
+ *
680
+ * This method modifies and transforms the received point.
681
+ */
682
+ protected fun transformPoint(point: PointF): PointF {
683
+ return orchestrator?.transformPointToViewCoords(this.view, point) ?: run {
684
+ point.x = Float.NaN
685
+ point.y = Float.NaN
686
+ point
687
+ }
688
+ }
669
689
  fun reset() {
670
690
  view = null
671
691
  orchestrator = null
@@ -689,14 +709,14 @@ open class GestureHandler<ConcreteGestureHandlerT : GestureHandler<ConcreteGestu
689
709
  }
690
710
 
691
711
  val lastRelativePositionX: Float
692
- get() = lastAbsolutePositionX - lastEventOffsetX
712
+ get() = lastAbsolutePositionX
693
713
  val lastRelativePositionY: Float
694
- get() = lastAbsolutePositionY - lastEventOffsetY
714
+ get() = lastAbsolutePositionY
695
715
 
696
716
  val lastPositionInWindowX: Float
697
- get() = lastAbsolutePositionX - windowOffset[0]
717
+ get() = lastAbsolutePositionX + lastEventOffsetX - windowOffset[0]
698
718
  val lastPositionInWindowY: Float
699
- get() = lastAbsolutePositionY - windowOffset[1]
719
+ get() = lastAbsolutePositionY + lastEventOffsetY - windowOffset[1]
700
720
 
701
721
  companion object {
702
722
  const val STATE_UNDETERMINED = 0
@@ -242,7 +242,7 @@ class GestureHandlerOrchestrator(
242
242
  }
243
243
  }
244
244
 
245
- private fun deliverEventToGestureHandler(handler: GestureHandler<*>, event: MotionEvent) {
245
+ private fun deliverEventToGestureHandler(handler: GestureHandler<*>, sourceEvent: MotionEvent) {
246
246
  if (!isViewAttachedUnderWrapper(handler.view)) {
247
247
  handler.cancel()
248
248
  return
@@ -250,18 +250,9 @@ class GestureHandlerOrchestrator(
250
250
  if (!handler.wantEvents()) {
251
251
  return
252
252
  }
253
- val action = event.actionMasked
254
- val coords = tempCoords
255
- extractCoordsForView(handler.view, event, coords)
256
- val oldX = event.x
257
- val oldY = event.y
258
- // TODO: we may consider scaling events if necessary using MotionEvent.transform
259
- // for now the events are only offset to the top left corner of the view but if
260
- // view or any ot the parents is scaled the other pointers position will not reflect
261
- // their actual place in the view. On the other hand not scaling seems like a better
262
- // approach when we want to use pointer coordinates to calculate velocity or distance
263
- // for pinch so I don't know yet if we should transform or not...
264
- event.setLocation(coords[0], coords[1])
253
+
254
+ val action = sourceEvent.actionMasked
255
+ val event = transformEventToViewCoords(handler.view, MotionEvent.obtain(sourceEvent))
265
256
 
266
257
  // Touch events are sent before the handler itself has a chance to process them,
267
258
  // mainly because `onTouchesUp` shoul be send befor gesture finishes. This means that
@@ -277,7 +268,7 @@ class GestureHandlerOrchestrator(
277
268
 
278
269
  if (!handler.isAwaiting || action != MotionEvent.ACTION_MOVE) {
279
270
  val isFirstEvent = handler.state == 0
280
- handler.handle(event)
271
+ handler.handle(event, sourceEvent)
281
272
  if (handler.isActive) {
282
273
  // After handler is done waiting for other one to fail its progress should be
283
274
  // reset, otherwise there may be a visible jump in values sent by the handler.
@@ -305,7 +296,7 @@ class GestureHandlerOrchestrator(
305
296
  }
306
297
  }
307
298
 
308
- event.setLocation(oldX, oldY)
299
+ event.recycle()
309
300
  }
310
301
 
311
302
  /**
@@ -329,19 +320,75 @@ class GestureHandlerOrchestrator(
329
320
  return parent === wrapperView
330
321
  }
331
322
 
332
- private fun extractCoordsForView(view: View?, event: MotionEvent, outputCoords: FloatArray) {
333
- if (view === wrapperView) {
334
- outputCoords[0] = event.x
335
- outputCoords[1] = event.y
336
- return
323
+ /**
324
+ * Transforms an event in the coordinates of wrapperView into the coordinate space of the received view.
325
+ *
326
+ * This modifies and returns the same event as it receives
327
+ *
328
+ * @param view - view to which coordinate space the event should be transformed
329
+ * @param event - event to transform
330
+ */
331
+ fun transformEventToViewCoords(view: View?, event: MotionEvent): MotionEvent {
332
+ if (view == null) {
333
+ return event
337
334
  }
338
- require(!(view == null || view.parent !is ViewGroup)) { "Parent is null? View is no longer in the tree" }
339
- val parent = view.parent as ViewGroup
340
- extractCoordsForView(parent, event, outputCoords)
341
- val childPoint = tempPoint
342
- transformTouchPointToViewCoords(outputCoords[0], outputCoords[1], parent, view, childPoint)
343
- outputCoords[0] = childPoint.x
344
- outputCoords[1] = childPoint.y
335
+
336
+ val parent = view.parent as? ViewGroup
337
+ // Events are passed down to the orchestrator by the wrapperView, so they are already in the
338
+ // relevant coordinate space. We want to stop traversing the tree when we reach it.
339
+ if (parent != wrapperView) {
340
+ transformEventToViewCoords(parent, event)
341
+ }
342
+
343
+ if (parent != null) {
344
+ val localX = event.x + parent.scrollX - view.left
345
+ val localY = event.y + parent.scrollY - view.top
346
+ event.setLocation(localX, localY)
347
+ }
348
+
349
+ if (!view.matrix.isIdentity) {
350
+ view.matrix.invert(inverseMatrix)
351
+ event.transform(inverseMatrix)
352
+ }
353
+
354
+ return event
355
+ }
356
+
357
+ /**
358
+ * Transforms a point in the coordinates of wrapperView into the coordinate space of the received view.
359
+ *
360
+ * This modifies and returns the same point as it receives
361
+ *
362
+ * @param view - view to which coordinate space the point should be transformed
363
+ * @param point - point to transform
364
+ */
365
+ fun transformPointToViewCoords(view: View?, point: PointF): PointF {
366
+ if (view == null) {
367
+ return point
368
+ }
369
+
370
+ val parent = view.parent as? ViewGroup
371
+ // Events are passed down to the orchestrator by the wrapperView, so they are already in the
372
+ // relevant coordinate space. We want to stop traversing the tree when we reach it.
373
+ if (parent != wrapperView) {
374
+ transformPointToViewCoords(parent, point)
375
+ }
376
+
377
+ if (parent != null) {
378
+ point.x += parent.scrollX - view.left
379
+ point.y += parent.scrollY - view.top
380
+ }
381
+
382
+ if (!view.matrix.isIdentity) {
383
+ view.matrix.invert(inverseMatrix)
384
+ tempCoords[0] = point.x
385
+ tempCoords[1] = point.y
386
+ inverseMatrix.mapPoints(tempCoords)
387
+ point.x = tempCoords[0]
388
+ point.y = tempCoords[1]
389
+ }
390
+
391
+ return point
345
392
  }
346
393
 
347
394
  private fun addAwaitingHandler(handler: GestureHandler<*>) {
@@ -451,7 +498,7 @@ class GestureHandlerOrchestrator(
451
498
  val child = viewConfigHelper.getChildInDrawingOrderAtIndex(viewGroup, i)
452
499
  if (canReceiveEvents(child)) {
453
500
  val childPoint = tempPoint
454
- transformTouchPointToViewCoords(coords[0], coords[1], viewGroup, child, childPoint)
501
+ transformPointToChildViewCoords(coords[0], coords[1], viewGroup, child, childPoint)
455
502
  val restoreX = coords[0]
456
503
  val restoreY = coords[1]
457
504
  coords[0] = childPoint.x
@@ -564,7 +611,7 @@ class GestureHandlerOrchestrator(
564
611
  return isLeafOrTransparent && isTransformedTouchPointInView(coords[0], coords[1], view)
565
612
  }
566
613
 
567
- private fun transformTouchPointToViewCoords(
614
+ private fun transformPointToChildViewCoords(
568
615
  x: Float,
569
616
  y: Float,
570
617
  parent: ViewGroup,
@@ -4,14 +4,13 @@ import android.view.MotionEvent
4
4
 
5
5
  object GestureUtils {
6
6
  fun getLastPointerX(event: MotionEvent, averageTouches: Boolean): Float {
7
- val offset = event.rawX - event.x
8
7
  val excludeIndex = if (event.actionMasked == MotionEvent.ACTION_POINTER_UP) event.actionIndex else -1
9
8
  return if (averageTouches) {
10
9
  var sum = 0f
11
10
  var count = 0
12
11
  for (i in 0 until event.pointerCount) {
13
12
  if (i != excludeIndex) {
14
- sum += event.getX(i) + offset
13
+ sum += event.getX(i)
15
14
  count++
16
15
  }
17
16
  }
@@ -21,19 +20,18 @@ object GestureUtils {
21
20
  if (lastPointerIdx == excludeIndex) {
22
21
  lastPointerIdx--
23
22
  }
24
- event.getX(lastPointerIdx) + offset
23
+ event.getX(lastPointerIdx)
25
24
  }
26
25
  }
27
26
 
28
27
  fun getLastPointerY(event: MotionEvent, averageTouches: Boolean): Float {
29
- val offset = event.rawY - event.y
30
28
  val excludeIndex = if (event.actionMasked == MotionEvent.ACTION_POINTER_UP) event.actionIndex else -1
31
29
  return if (averageTouches) {
32
30
  var sum = 0f
33
31
  var count = 0
34
32
  for (i in 0 until event.pointerCount) {
35
33
  if (i != excludeIndex) {
36
- sum += event.getY(i) + offset
34
+ sum += event.getY(i)
37
35
  count++
38
36
  }
39
37
  }
@@ -43,7 +41,7 @@ object GestureUtils {
43
41
  if (lastPointerIdx == excludeIndex) {
44
42
  lastPointerIdx -= 1
45
43
  }
46
- event.getY(lastPointerIdx) + offset
44
+ event.getY(lastPointerIdx)
47
45
  }
48
46
  }
49
47
  }
@@ -37,13 +37,13 @@ class LongPressGestureHandler(context: Context) : GestureHandler<LongPressGestur
37
37
  return this
38
38
  }
39
39
 
40
- override fun onHandle(event: MotionEvent) {
40
+ override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) {
41
41
  if (state == STATE_UNDETERMINED) {
42
42
  previousTime = SystemClock.uptimeMillis()
43
43
  startTime = previousTime
44
44
  begin()
45
- startX = event.rawX
46
- startY = event.rawY
45
+ startX = sourceEvent.rawX
46
+ startY = sourceEvent.rawY
47
47
  handler = Handler(Looper.getMainLooper())
48
48
  if (minDurationMs > 0) {
49
49
  handler!!.postDelayed({ activate() }, minDurationMs)
@@ -51,7 +51,7 @@ class LongPressGestureHandler(context: Context) : GestureHandler<LongPressGestur
51
51
  activate()
52
52
  }
53
53
  }
54
- if (event.actionMasked == MotionEvent.ACTION_UP) {
54
+ if (sourceEvent.actionMasked == MotionEvent.ACTION_UP) {
55
55
  handler?.let {
56
56
  it.removeCallbacksAndMessages(null)
57
57
  handler = null
@@ -63,8 +63,8 @@ class LongPressGestureHandler(context: Context) : GestureHandler<LongPressGestur
63
63
  }
64
64
  } else {
65
65
  // calculate distance from start
66
- val deltaX = event.rawX - startX
67
- val deltaY = event.rawY - startY
66
+ val deltaX = sourceEvent.rawX - startX
67
+ val deltaY = sourceEvent.rawY - startY
68
68
  val distSq = deltaX * deltaX + deltaY * deltaY
69
69
  if (distSq > maxDistSq) {
70
70
  if (state == STATE_ACTIVE) {
@@ -3,7 +3,7 @@ package com.swmansion.gesturehandler
3
3
  import android.view.MotionEvent
4
4
 
5
5
  class ManualGestureHandler : GestureHandler<ManualGestureHandler>() {
6
- override fun onHandle(event: MotionEvent) {
6
+ override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) {
7
7
  if (state == STATE_UNDETERMINED) {
8
8
  begin()
9
9
  }
@@ -75,7 +75,7 @@ class NativeViewGestureHandler : GestureHandler<NativeViewGestureHandler>() {
75
75
  }
76
76
  }
77
77
 
78
- override fun onHandle(event: MotionEvent) {
78
+ override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) {
79
79
  val view = view!!
80
80
  if (event.actionMasked == MotionEvent.ACTION_UP) {
81
81
  view.onTouchEvent(event)
@@ -205,31 +205,31 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
205
205
  return failOffsetYEnd != MIN_VALUE_IGNORE && dy > failOffsetYEnd
206
206
  }
207
207
 
208
- override fun onHandle(event: MotionEvent) {
208
+ override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) {
209
209
  val state = state
210
- val action = event.actionMasked
210
+ val action = sourceEvent.actionMasked
211
211
  if (action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_POINTER_DOWN) {
212
212
  // update offset if new pointer gets added or removed
213
213
  offsetX += lastX - startX
214
214
  offsetY += lastY - startY
215
215
 
216
216
  // reset starting point
217
- lastX = getLastPointerX(event, averageTouches)
218
- lastY = getLastPointerY(event, averageTouches)
217
+ lastX = getLastPointerX(sourceEvent, averageTouches)
218
+ lastY = getLastPointerY(sourceEvent, averageTouches)
219
219
  startX = lastX
220
220
  startY = lastY
221
221
  } else {
222
- lastX = getLastPointerX(event, averageTouches)
223
- lastY = getLastPointerY(event, averageTouches)
222
+ lastX = getLastPointerX(sourceEvent, averageTouches)
223
+ lastY = getLastPointerY(sourceEvent, averageTouches)
224
224
  }
225
- if (state == STATE_UNDETERMINED && event.pointerCount >= minPointers) {
225
+ if (state == STATE_UNDETERMINED && sourceEvent.pointerCount >= minPointers) {
226
226
  resetProgress()
227
227
  offsetX = 0f
228
228
  offsetY = 0f
229
229
  velocityX = 0f
230
230
  velocityY = 0f
231
231
  velocityTracker = VelocityTracker.obtain()
232
- addVelocityMovement(velocityTracker, event)
232
+ addVelocityMovement(velocityTracker, sourceEvent)
233
233
  begin()
234
234
 
235
235
  if (activateAfterLongPress > 0) {
@@ -239,7 +239,7 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
239
239
  handler!!.postDelayed(activateDelayed, activateAfterLongPress)
240
240
  }
241
241
  } else if (velocityTracker != null) {
242
- addVelocityMovement(velocityTracker, event)
242
+ addVelocityMovement(velocityTracker, sourceEvent)
243
243
  velocityTracker!!.computeCurrentVelocity(1000)
244
244
  velocityX = velocityTracker!!.xVelocity
245
245
  velocityY = velocityTracker!!.yVelocity
@@ -250,14 +250,14 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
250
250
  } else {
251
251
  fail()
252
252
  }
253
- } else if (action == MotionEvent.ACTION_POINTER_DOWN && event.pointerCount > maxPointers) {
253
+ } else if (action == MotionEvent.ACTION_POINTER_DOWN && sourceEvent.pointerCount > maxPointers) {
254
254
  // When new finger is placed down (POINTER_DOWN) we check if MAX_POINTERS is not exceeded
255
255
  if (state == STATE_ACTIVE) {
256
256
  cancel()
257
257
  } else {
258
258
  fail()
259
259
  }
260
- } else if (action == MotionEvent.ACTION_POINTER_UP && state == STATE_ACTIVE && event.pointerCount < minPointers) {
260
+ } else if (action == MotionEvent.ACTION_POINTER_UP && state == STATE_ACTIVE && sourceEvent.pointerCount < minPointers) {
261
261
  // When finger is lifted up (POINTER_UP) and the number of pointers falls below MIN_POINTERS
262
262
  // threshold, we only want to take an action when the handler has already activated. Otherwise
263
263
  // we can still expect more fingers to be placed on screen and fulfill MIN_POINTERS criteria.
@@ -1,5 +1,6 @@
1
1
  package com.swmansion.gesturehandler
2
2
 
3
+ import android.graphics.PointF
3
4
  import android.view.MotionEvent
4
5
  import android.view.ViewConfiguration
5
6
  import kotlin.math.abs
@@ -9,10 +10,10 @@ class PinchGestureHandler : GestureHandler<PinchGestureHandler>() {
9
10
  private set
10
11
  var velocity = 0.0
11
12
  private set
12
- val focalPointX: Float
13
- get() = scaleGestureDetector?.focusX ?: Float.NaN
14
- val focalPointY: Float
15
- get() = scaleGestureDetector?.focusY ?: Float.NaN
13
+ var focalPointX: Float = Float.NaN
14
+ private set
15
+ var focalPointY: Float = Float.NaN
16
+ private set
16
17
 
17
18
  private var scaleGestureDetector: ScaleGestureDetector? = null
18
19
  private var startingSpan = 0f
@@ -47,7 +48,7 @@ class PinchGestureHandler : GestureHandler<PinchGestureHandler>() {
47
48
  }
48
49
  }
49
50
 
50
- override fun onHandle(event: MotionEvent) {
51
+ override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) {
51
52
  if (state == STATE_UNDETERMINED) {
52
53
  val context = view!!.context
53
54
  resetProgress()
@@ -56,14 +57,19 @@ class PinchGestureHandler : GestureHandler<PinchGestureHandler>() {
56
57
  spanSlop = configuration.scaledTouchSlop.toFloat()
57
58
  begin()
58
59
  }
59
- scaleGestureDetector?.onTouchEvent(event)
60
- var activePointers = event.pointerCount
61
- if (event.actionMasked == MotionEvent.ACTION_POINTER_UP) {
60
+ scaleGestureDetector?.onTouchEvent(sourceEvent)
61
+ scaleGestureDetector?.let {
62
+ val point = transformPoint(PointF(it.focusX, it.focusY))
63
+ this.focalPointX = point.x
64
+ this.focalPointY = point.y
65
+ }
66
+ var activePointers = sourceEvent.pointerCount
67
+ if (sourceEvent.actionMasked == MotionEvent.ACTION_POINTER_UP) {
62
68
  activePointers -= 1
63
69
  }
64
70
  if (state == STATE_ACTIVE && activePointers < 2) {
65
71
  end()
66
- } else if (event.actionMasked == MotionEvent.ACTION_UP) {
72
+ } else if (sourceEvent.actionMasked == MotionEvent.ACTION_UP) {
67
73
  fail()
68
74
  }
69
75
  }
@@ -78,6 +84,8 @@ class PinchGestureHandler : GestureHandler<PinchGestureHandler>() {
78
84
 
79
85
  override fun onReset() {
80
86
  scaleGestureDetector = null
87
+ focalPointX = Float.NaN
88
+ focalPointY = Float.NaN
81
89
  resetProgress()
82
90
  }
83
91
 
@@ -1,5 +1,6 @@
1
1
  package com.swmansion.gesturehandler
2
2
 
3
+ import android.graphics.PointF
3
4
  import android.view.MotionEvent
4
5
  import com.swmansion.gesturehandler.RotationGestureDetector.OnRotationGestureListener
5
6
  import kotlin.math.abs
@@ -10,11 +11,10 @@ class RotationGestureHandler : GestureHandler<RotationGestureHandler>() {
10
11
  private set
11
12
  var velocity = 0.0
12
13
  private set
13
-
14
- val anchorX: Float
15
- get() = rotationGestureDetector?.anchorX ?: Float.NaN
16
- val anchorY: Float
17
- get() = rotationGestureDetector?.anchorY ?: Float.NaN
14
+ var anchorX: Float = Float.NaN
15
+ private set
16
+ var anchorY: Float = Float.NaN
17
+ private set
18
18
 
19
19
  init {
20
20
  setShouldCancelWhenOutside(false)
@@ -41,14 +41,19 @@ class RotationGestureHandler : GestureHandler<RotationGestureHandler>() {
41
41
  }
42
42
  }
43
43
 
44
- override fun onHandle(event: MotionEvent) {
44
+ override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) {
45
45
  if (state == STATE_UNDETERMINED) {
46
46
  resetProgress()
47
47
  rotationGestureDetector = RotationGestureDetector(gestureListener)
48
48
  begin()
49
49
  }
50
- rotationGestureDetector?.onTouchEvent(event)
51
- if (event.actionMasked == MotionEvent.ACTION_UP) {
50
+ rotationGestureDetector?.onTouchEvent(sourceEvent)
51
+ rotationGestureDetector?.let {
52
+ val point = transformPoint(PointF(it.anchorX, it.anchorY))
53
+ anchorX = point.x
54
+ anchorY = point.y
55
+ }
56
+ if (sourceEvent.actionMasked == MotionEvent.ACTION_UP) {
52
57
  if (state == STATE_ACTIVE) {
53
58
  end()
54
59
  } else {
@@ -67,6 +72,8 @@ class RotationGestureHandler : GestureHandler<RotationGestureHandler>() {
67
72
 
68
73
  override fun onReset() {
69
74
  rotationGestureDetector = null
75
+ anchorX = Float.NaN
76
+ anchorY = Float.NaN
70
77
  resetProgress()
71
78
  }
72
79