react-native-gesture-handler 2.19.0 → 2.20.0
Sign up to get free protection for your applications and to get access to all the features.
- package/android/build.gradle +7 -12
- package/android/fabric/src/main/java/com/swmansion/gesturehandler/ReactContextExtensions.kt +1 -1
- package/android/paper/src/main/java/com/swmansion/gesturehandler/ReactContextExtensions.kt +1 -1
- package/android/src/main/java/com/swmansion/gesturehandler/core/GestureUtils.kt +1 -0
- package/android/src/main/java/com/swmansion/gesturehandler/core/HoverGestureHandler.kt +11 -0
- package/android/src/main/java/com/swmansion/gesturehandler/core/PanGestureHandler.kt +8 -0
- package/android/src/main/java/com/swmansion/gesturehandler/core/StylusData.kt +103 -0
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +24 -15
- package/android/src/main/java/com/swmansion/gesturehandler/react/eventbuilders/HoverGestureHandlerEventDataBuilder.kt +7 -0
- package/android/src/main/java/com/swmansion/gesturehandler/react/eventbuilders/PanGestureHandlerEventDataBuilder.kt +7 -0
- package/android/src/main/jni/CMakeLists.txt +18 -9
- package/apple/Handlers/RNLongPressHandler.m +2 -0
- package/apple/Handlers/RNPanHandler.m +57 -7
- package/apple/Handlers/RNRotationHandler.m +1 -1
- package/apple/RNGHStylusData.h +77 -0
- package/apple/RNGHStylusData.m +37 -0
- package/apple/RNGestureHandlerButtonComponentView.mm +35 -0
- package/apple/RNGestureHandlerEvents.h +3 -1
- package/apple/RNGestureHandlerEvents.m +11 -3
- package/lib/commonjs/components/GestureButtons.js +5 -1
- package/lib/commonjs/components/GestureButtons.js.map +1 -1
- package/lib/commonjs/components/GestureComponents.js.map +1 -1
- package/lib/commonjs/components/Pressable/Pressable.js +5 -14
- package/lib/commonjs/components/Pressable/Pressable.js.map +1 -1
- package/lib/commonjs/components/Pressable/utils.js +1 -23
- package/lib/commonjs/components/Pressable/utils.js.map +1 -1
- package/lib/commonjs/handlers/GestureHandlerEventPayload.js +4 -0
- package/lib/commonjs/handlers/createHandler.js +2 -1
- package/lib/commonjs/handlers/createHandler.js.map +1 -1
- package/lib/commonjs/handlers/gestures/gesture.js.map +1 -1
- package/lib/commonjs/handlers/gestures/hoverGesture.js.map +1 -1
- package/lib/commonjs/jestUtils/jestUtils.js +12 -4
- package/lib/commonjs/jestUtils/jestUtils.js.map +1 -1
- package/lib/commonjs/web/handlers/GestureHandler.js +1 -3
- package/lib/commonjs/web/handlers/GestureHandler.js.map +1 -1
- package/lib/commonjs/web/handlers/HoverGestureHandler.js +18 -1
- package/lib/commonjs/web/handlers/HoverGestureHandler.js.map +1 -1
- package/lib/commonjs/web/handlers/PanGestureHandler.js +8 -1
- package/lib/commonjs/web/handlers/PanGestureHandler.js.map +1 -1
- package/lib/commonjs/web/interfaces.js.map +1 -1
- package/lib/commonjs/web/tools/EventManager.js.map +1 -1
- package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js +0 -3
- package/lib/commonjs/web/tools/GestureHandlerWebDelegate.js.map +1 -1
- package/lib/commonjs/web/tools/PointerEventManager.js +3 -37
- package/lib/commonjs/web/tools/PointerEventManager.js.map +1 -1
- package/lib/commonjs/web/utils.js +173 -0
- package/lib/commonjs/web/utils.js.map +1 -1
- package/lib/module/components/GestureButtons.js +5 -1
- package/lib/module/components/GestureButtons.js.map +1 -1
- package/lib/module/components/GestureComponents.js.map +1 -1
- package/lib/module/components/Pressable/Pressable.js +7 -14
- package/lib/module/components/Pressable/Pressable.js.map +1 -1
- package/lib/module/components/Pressable/utils.js +1 -22
- package/lib/module/components/Pressable/utils.js.map +1 -1
- package/lib/module/handlers/GestureHandlerEventPayload.js +1 -1
- package/lib/module/handlers/createHandler.js +2 -1
- package/lib/module/handlers/createHandler.js.map +1 -1
- package/lib/module/handlers/gestures/gesture.js.map +1 -1
- package/lib/module/handlers/gestures/hoverGesture.js.map +1 -1
- package/lib/module/jestUtils/jestUtils.js +12 -4
- package/lib/module/jestUtils/jestUtils.js.map +1 -1
- package/lib/module/web/handlers/GestureHandler.js +1 -3
- package/lib/module/web/handlers/GestureHandler.js.map +1 -1
- package/lib/module/web/handlers/HoverGestureHandler.js +18 -1
- package/lib/module/web/handlers/HoverGestureHandler.js.map +1 -1
- package/lib/module/web/handlers/PanGestureHandler.js +8 -1
- package/lib/module/web/handlers/PanGestureHandler.js.map +1 -1
- package/lib/module/web/interfaces.js.map +1 -1
- package/lib/module/web/tools/EventManager.js.map +1 -1
- package/lib/module/web/tools/GestureHandlerWebDelegate.js +0 -2
- package/lib/module/web/tools/GestureHandlerWebDelegate.js.map +1 -1
- package/lib/module/web/tools/PointerEventManager.js +4 -38
- package/lib/module/web/tools/PointerEventManager.js.map +1 -1
- package/lib/module/web/utils.js +170 -0
- package/lib/module/web/utils.js.map +1 -1
- package/lib/typescript/components/GestureComponents.d.ts +1 -1
- package/lib/typescript/components/Pressable/utils.d.ts +3 -5
- package/lib/typescript/handlers/GestureHandlerEventPayload.d.ts +35 -0
- package/lib/typescript/handlers/gestures/gesture.d.ts +2 -2
- package/lib/typescript/handlers/gestures/hoverGesture.d.ts +1 -6
- package/lib/typescript/handlers/handlersRegistry.d.ts +1 -1
- package/lib/typescript/jestUtils/jestUtils.d.ts +1 -1
- package/lib/typescript/web/handlers/HoverGestureHandler.d.ts +2 -0
- package/lib/typescript/web/handlers/PanGestureHandler.d.ts +3 -1
- package/lib/typescript/web/interfaces.d.ts +8 -3
- package/lib/typescript/web/tools/EventManager.d.ts +2 -2
- package/lib/typescript/web/utils.d.ts +2 -1
- package/package.json +1 -1
- package/src/components/GestureButtons.tsx +2 -1
- package/src/components/GestureComponents.tsx +1 -1
- package/src/components/Pressable/Pressable.tsx +16 -29
- package/src/components/Pressable/utils.ts +5 -49
- package/src/handlers/GestureHandlerEventPayload.ts +42 -0
- package/src/handlers/createHandler.tsx +1 -0
- package/src/handlers/gestures/gesture.ts +3 -1
- package/src/handlers/gestures/hoverGesture.ts +1 -7
- package/src/jestUtils/jestUtils.ts +9 -1
- package/src/web/handlers/GestureHandler.ts +1 -1
- package/src/web/handlers/HoverGestureHandler.ts +16 -2
- package/src/web/handlers/PanGestureHandler.ts +10 -1
- package/src/web/interfaces.ts +9 -3
- package/src/web/tools/EventManager.ts +2 -4
- package/src/web/tools/GestureHandlerWebDelegate.ts +0 -2
- package/src/web/tools/PointerEventManager.ts +2 -38
- package/src/web/utils.ts +174 -1
- package/lib/commonjs/web/tools/TouchEventManager.js +0 -164
- package/lib/commonjs/web/tools/TouchEventManager.js.map +0 -1
- package/lib/module/web/tools/TouchEventManager.js +0 -149
- package/lib/module/web/tools/TouchEventManager.js.map +0 -1
- package/lib/typescript/web/tools/TouchEventManager.d.ts +0 -11
- package/src/web/tools/TouchEventManager.ts +0 -175
package/android/build.gradle
CHANGED
@@ -33,16 +33,10 @@ def resolveReactNativeDirectory() {
|
|
33
33
|
return file(reactNativeLocation)
|
34
34
|
}
|
35
35
|
|
36
|
-
//
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
return reactNativeFromProjectNodeModules
|
41
|
-
}
|
42
|
-
|
43
|
-
def reactNativeFromNodeModulesWithReanimated = file("${projectDir}/../../react-native")
|
44
|
-
if (reactNativeFromNodeModulesWithReanimated.exists()) {
|
45
|
-
return reactNativeFromNodeModulesWithReanimated
|
36
|
+
// Fallback to node resolver for custom directory structures like monorepos.
|
37
|
+
def reactNativePackage = file(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim())
|
38
|
+
if (reactNativePackage.exists()) {
|
39
|
+
return reactNativePackage.parentFile
|
46
40
|
}
|
47
41
|
|
48
42
|
throw new Exception(
|
@@ -124,8 +118,7 @@ android {
|
|
124
118
|
externalNativeBuild {
|
125
119
|
cmake {
|
126
120
|
cppFlags "-O2", "-frtti", "-fexceptions", "-Wall", "-Werror", "-std=c++20", "-DANDROID"
|
127
|
-
arguments "-
|
128
|
-
"-DREACT_NATIVE_DIR=${REACT_NATIVE_DIR}",
|
121
|
+
arguments "-DREACT_NATIVE_DIR=${REACT_NATIVE_DIR}",
|
129
122
|
"-DREACT_NATIVE_MINOR_VERSION=${REACT_NATIVE_MINOR_VERSION}",
|
130
123
|
"-DANDROID_STL=c++_shared"
|
131
124
|
abiFilters (*reactNativeArchitectures())
|
@@ -153,6 +146,8 @@ android {
|
|
153
146
|
// only the ones that make the build fail (ideally we should only include libgesturehandler but we
|
154
147
|
// are only allowed to specify exclude patterns)
|
155
148
|
exclude "**/libreact_render*.so"
|
149
|
+
exclude "**/libreactnative.so"
|
150
|
+
exclude "**/libjsi.so"
|
156
151
|
}
|
157
152
|
|
158
153
|
sourceSets.main {
|
@@ -8,5 +8,5 @@ import com.facebook.react.uimanager.events.Event
|
|
8
8
|
|
9
9
|
fun ReactContext.dispatchEvent(event: Event<*>) {
|
10
10
|
val fabricUIManager = UIManagerHelper.getUIManager(this, UIManagerType.FABRIC) as FabricUIManager
|
11
|
-
fabricUIManager.
|
11
|
+
fabricUIManager.getEventDispatcher().dispatchEvent(event)
|
12
12
|
}
|
@@ -6,7 +6,7 @@ import com.facebook.react.uimanager.events.Event
|
|
6
6
|
|
7
7
|
fun ReactContext.dispatchEvent(event: Event<*>) {
|
8
8
|
try {
|
9
|
-
this.getNativeModule(UIManagerModule::class.java)!!.
|
9
|
+
this.getNativeModule(UIManagerModule::class.java)!!.getEventDispatcher().dispatchEvent(event)
|
10
10
|
} catch (e: NullPointerException) {
|
11
11
|
throw Exception("Couldn't get an instance of UIManagerModule. Gesture Handler is unable to send an event.", e)
|
12
12
|
}
|
@@ -11,6 +11,8 @@ import com.swmansion.gesturehandler.react.RNViewConfigurationHelper
|
|
11
11
|
class HoverGestureHandler : GestureHandler<HoverGestureHandler>() {
|
12
12
|
private var handler: Handler? = null
|
13
13
|
private var finishRunnable = Runnable { finish() }
|
14
|
+
var stylusData: StylusData = StylusData()
|
15
|
+
private set
|
14
16
|
|
15
17
|
private infix fun isAncestorOf(other: GestureHandler<*>): Boolean {
|
16
18
|
var current: View? = other.view
|
@@ -103,6 +105,10 @@ class HoverGestureHandler : GestureHandler<HoverGestureHandler>() {
|
|
103
105
|
finish()
|
104
106
|
}
|
105
107
|
|
108
|
+
this.state == STATE_ACTIVE && event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS -> {
|
109
|
+
stylusData = StylusData.fromEvent(event)
|
110
|
+
}
|
111
|
+
|
106
112
|
this.state == STATE_UNDETERMINED &&
|
107
113
|
(event.action == MotionEvent.ACTION_HOVER_MOVE || event.action == MotionEvent.ACTION_HOVER_ENTER) -> {
|
108
114
|
begin()
|
@@ -111,6 +117,11 @@ class HoverGestureHandler : GestureHandler<HoverGestureHandler>() {
|
|
111
117
|
}
|
112
118
|
}
|
113
119
|
|
120
|
+
override fun onReset() {
|
121
|
+
super.onReset()
|
122
|
+
stylusData = StylusData()
|
123
|
+
}
|
124
|
+
|
114
125
|
private fun finish() {
|
115
126
|
when (this.state) {
|
116
127
|
STATE_UNDETERMINED -> cancel()
|
@@ -45,6 +45,8 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
|
|
45
45
|
private var activateAfterLongPress = DEFAULT_ACTIVATE_AFTER_LONG_PRESS
|
46
46
|
private val activateDelayed = Runnable { activate() }
|
47
47
|
private var handler: Handler? = null
|
48
|
+
var stylusData: StylusData = StylusData()
|
49
|
+
private set
|
48
50
|
|
49
51
|
/**
|
50
52
|
* On Android when there are multiple pointers on the screen pan gestures most often just consider
|
@@ -212,6 +214,10 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
|
|
212
214
|
return
|
213
215
|
}
|
214
216
|
|
217
|
+
if (event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS) {
|
218
|
+
stylusData = StylusData.fromEvent(event)
|
219
|
+
}
|
220
|
+
|
215
221
|
val state = state
|
216
222
|
val action = sourceEvent.actionMasked
|
217
223
|
if (action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_POINTER_DOWN) {
|
@@ -295,6 +301,8 @@ class PanGestureHandler(context: Context?) : GestureHandler<PanGestureHandler>()
|
|
295
301
|
it.recycle()
|
296
302
|
velocityTracker = null
|
297
303
|
}
|
304
|
+
|
305
|
+
stylusData = StylusData()
|
298
306
|
}
|
299
307
|
|
300
308
|
override fun resetProgress() {
|
@@ -0,0 +1,103 @@
|
|
1
|
+
package com.swmansion.gesturehandler.core
|
2
|
+
|
3
|
+
import android.view.MotionEvent
|
4
|
+
import com.facebook.react.bridge.Arguments
|
5
|
+
import com.facebook.react.bridge.ReadableMap
|
6
|
+
import kotlin.math.PI
|
7
|
+
import kotlin.math.abs
|
8
|
+
import kotlin.math.atan
|
9
|
+
import kotlin.math.cos
|
10
|
+
import kotlin.math.round
|
11
|
+
import kotlin.math.sin
|
12
|
+
import kotlin.math.tan
|
13
|
+
|
14
|
+
data class StylusData(
|
15
|
+
val tiltX: Double = 0.0,
|
16
|
+
val tiltY: Double = 0.0,
|
17
|
+
val altitudeAngle: Double = 0.0,
|
18
|
+
val azimuthAngle: Double = 0.0,
|
19
|
+
val pressure: Double = -1.0
|
20
|
+
) {
|
21
|
+
fun toReadableMap(): ReadableMap {
|
22
|
+
val stylusDataObject = Arguments.createMap().apply {
|
23
|
+
putDouble("tiltX", tiltX)
|
24
|
+
putDouble("tiltY", tiltY)
|
25
|
+
putDouble("altitudeAngle", altitudeAngle)
|
26
|
+
putDouble("azimuthAngle", azimuthAngle)
|
27
|
+
putDouble("pressure", pressure)
|
28
|
+
}
|
29
|
+
|
30
|
+
val readableStylusData: ReadableMap = stylusDataObject
|
31
|
+
|
32
|
+
return readableStylusData
|
33
|
+
}
|
34
|
+
|
35
|
+
companion object {
|
36
|
+
// Source: https://w3c.github.io/pointerevents/#converting-between-tiltx-tilty-and-altitudeangle-azimuthangle
|
37
|
+
private fun spherical2tilt(altitudeAngle: Double, azimuthAngle: Double): Pair<Double, Double> {
|
38
|
+
val eps = 0.000000001
|
39
|
+
val radToDeg = 180 / PI
|
40
|
+
|
41
|
+
var tiltXrad = 0.0
|
42
|
+
var tiltYrad = 0.0
|
43
|
+
|
44
|
+
if (altitudeAngle < eps) {
|
45
|
+
// the pen is in the X-Y plane
|
46
|
+
if (azimuthAngle < eps || abs(azimuthAngle - 2 * PI) < eps) {
|
47
|
+
// pen is on positive X axis
|
48
|
+
tiltXrad = PI / 2
|
49
|
+
}
|
50
|
+
if (abs(azimuthAngle - PI / 2) < eps) {
|
51
|
+
// pen is on positive Y axis
|
52
|
+
tiltYrad = PI / 2
|
53
|
+
}
|
54
|
+
if (abs(azimuthAngle - PI) < eps) {
|
55
|
+
// pen is on negative X axis
|
56
|
+
tiltXrad = -PI / 2
|
57
|
+
}
|
58
|
+
if (abs(azimuthAngle - (3 * PI) / 2) < eps) {
|
59
|
+
// pen is on negative Y axis
|
60
|
+
tiltYrad = -PI / 2
|
61
|
+
}
|
62
|
+
if (azimuthAngle > eps && abs(azimuthAngle - PI / 2) < eps) {
|
63
|
+
tiltXrad = PI / 2
|
64
|
+
tiltYrad = PI / 2
|
65
|
+
}
|
66
|
+
if (abs(azimuthAngle - PI / 2) > eps && abs(azimuthAngle - PI) < eps) {
|
67
|
+
tiltXrad = -PI / 2
|
68
|
+
tiltYrad = PI / 2
|
69
|
+
}
|
70
|
+
if (abs(azimuthAngle - PI) > eps && abs(azimuthAngle - (3 * PI) / 2) < eps) {
|
71
|
+
tiltXrad = -PI / 2
|
72
|
+
tiltYrad = -PI / 2
|
73
|
+
}
|
74
|
+
if (abs(azimuthAngle - (3 * PI) / 2) > eps && abs(azimuthAngle - 2 * PI) < eps) {
|
75
|
+
tiltXrad = PI / 2
|
76
|
+
tiltYrad = -PI / 2
|
77
|
+
}
|
78
|
+
} else {
|
79
|
+
val tanAlt = tan(altitudeAngle)
|
80
|
+
|
81
|
+
tiltXrad = atan(cos(azimuthAngle) / tanAlt)
|
82
|
+
tiltYrad = atan(sin(azimuthAngle) / tanAlt)
|
83
|
+
}
|
84
|
+
|
85
|
+
val tiltX = round(tiltXrad * radToDeg)
|
86
|
+
val tiltY = round(tiltYrad * radToDeg)
|
87
|
+
|
88
|
+
return Pair(tiltX, tiltY)
|
89
|
+
}
|
90
|
+
|
91
|
+
fun fromEvent(event: MotionEvent): StylusData {
|
92
|
+
// On web and iOS 0 degrees means that stylus is parallel to the surface. On android this value will be PI / 2.
|
93
|
+
val altitudeAngle = (PI / 2) - event.getAxisValue(MotionEvent.AXIS_TILT).toDouble()
|
94
|
+
val pressure = event.getPressure(0).toDouble()
|
95
|
+
val orientation = event.getOrientation(0).toDouble()
|
96
|
+
// To get azimuth angle, we need to use orientation property (https://developer.android.com/develop/ui/compose/touch-input/stylus-input/advanced-stylus-features#orientation).
|
97
|
+
val azimuthAngle = (orientation + PI / 2).mod(2 * PI)
|
98
|
+
val tilts = spherical2tilt(altitudeAngle, azimuthAngle)
|
99
|
+
|
100
|
+
return StylusData(tilts.first, tilts.second, altitudeAngle, azimuthAngle, pressure)
|
101
|
+
}
|
102
|
+
}
|
103
|
+
}
|
@@ -286,22 +286,11 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
|
|
286
286
|
return false
|
287
287
|
}
|
288
288
|
|
289
|
-
private fun updateBackgroundColor(backgroundColor: Int, selectable: Drawable?) {
|
289
|
+
private fun updateBackgroundColor(backgroundColor: Int, borderDrawable: Drawable, selectable: Drawable?) {
|
290
290
|
val colorDrawable = PaintDrawable(backgroundColor)
|
291
|
-
val borderDrawable = PaintDrawable(Color.TRANSPARENT)
|
292
291
|
|
293
292
|
if (hasBorderRadii) {
|
294
293
|
colorDrawable.setCornerRadii(buildBorderRadii())
|
295
|
-
borderDrawable.setCornerRadii(buildBorderRadii())
|
296
|
-
}
|
297
|
-
|
298
|
-
if (borderWidth > 0f) {
|
299
|
-
borderDrawable.paint.apply {
|
300
|
-
style = Paint.Style.STROKE
|
301
|
-
strokeWidth = borderWidth
|
302
|
-
color = borderColor ?: Color.BLACK
|
303
|
-
pathEffect = buildBorderStyle()
|
304
|
-
}
|
305
294
|
}
|
306
295
|
|
307
296
|
val layerDrawable = LayerDrawable(if (selectable != null) arrayOf(colorDrawable, selectable, borderDrawable) else arrayOf(colorDrawable, borderDrawable))
|
@@ -324,6 +313,7 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
|
|
324
313
|
}
|
325
314
|
|
326
315
|
val selectable = createSelectableDrawable()
|
316
|
+
val borderDrawable = createBorderDrawable()
|
327
317
|
|
328
318
|
if (hasBorderRadii && selectable is RippleDrawable) {
|
329
319
|
val mask = PaintDrawable(Color.WHITE)
|
@@ -334,13 +324,32 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
|
|
334
324
|
if (useDrawableOnForeground && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
335
325
|
foreground = selectable
|
336
326
|
if (_backgroundColor != Color.TRANSPARENT) {
|
337
|
-
updateBackgroundColor(_backgroundColor, null)
|
327
|
+
updateBackgroundColor(_backgroundColor, borderDrawable, null)
|
338
328
|
}
|
339
329
|
} else if (_backgroundColor == Color.TRANSPARENT && rippleColor == null) {
|
340
|
-
background = selectable
|
330
|
+
background = LayerDrawable(arrayOf(selectable, borderDrawable))
|
341
331
|
} else {
|
342
|
-
updateBackgroundColor(_backgroundColor, selectable)
|
332
|
+
updateBackgroundColor(_backgroundColor, borderDrawable, selectable)
|
333
|
+
}
|
334
|
+
}
|
335
|
+
|
336
|
+
private fun createBorderDrawable(): Drawable {
|
337
|
+
val borderDrawable = PaintDrawable(Color.TRANSPARENT)
|
338
|
+
|
339
|
+
if (hasBorderRadii) {
|
340
|
+
borderDrawable.setCornerRadii(buildBorderRadii())
|
341
|
+
}
|
342
|
+
|
343
|
+
if (borderWidth > 0f) {
|
344
|
+
borderDrawable.paint.apply {
|
345
|
+
style = Paint.Style.STROKE
|
346
|
+
strokeWidth = borderWidth
|
347
|
+
color = borderColor ?: Color.BLACK
|
348
|
+
pathEffect = buildBorderStyle()
|
349
|
+
}
|
343
350
|
}
|
351
|
+
|
352
|
+
return borderDrawable
|
344
353
|
}
|
345
354
|
|
346
355
|
private fun createSelectableDrawable(): Drawable? {
|
@@ -3,18 +3,21 @@ package com.swmansion.gesturehandler.react.eventbuilders
|
|
3
3
|
import com.facebook.react.bridge.WritableMap
|
4
4
|
import com.facebook.react.uimanager.PixelUtil
|
5
5
|
import com.swmansion.gesturehandler.core.HoverGestureHandler
|
6
|
+
import com.swmansion.gesturehandler.core.StylusData
|
6
7
|
|
7
8
|
class HoverGestureHandlerEventDataBuilder(handler: HoverGestureHandler) : GestureHandlerEventDataBuilder<HoverGestureHandler>(handler) {
|
8
9
|
private val x: Float
|
9
10
|
private val y: Float
|
10
11
|
private val absoluteX: Float
|
11
12
|
private val absoluteY: Float
|
13
|
+
private val stylusData: StylusData
|
12
14
|
|
13
15
|
init {
|
14
16
|
x = handler.lastRelativePositionX
|
15
17
|
y = handler.lastRelativePositionY
|
16
18
|
absoluteX = handler.lastPositionInWindowX
|
17
19
|
absoluteY = handler.lastPositionInWindowY
|
20
|
+
stylusData = handler.stylusData
|
18
21
|
}
|
19
22
|
|
20
23
|
override fun buildEventData(eventData: WritableMap) {
|
@@ -25,6 +28,10 @@ class HoverGestureHandlerEventDataBuilder(handler: HoverGestureHandler) : Gestur
|
|
25
28
|
putDouble("y", PixelUtil.toDIPFromPixel(y).toDouble())
|
26
29
|
putDouble("absoluteX", PixelUtil.toDIPFromPixel(absoluteX).toDouble())
|
27
30
|
putDouble("absoluteY", PixelUtil.toDIPFromPixel(absoluteY).toDouble())
|
31
|
+
|
32
|
+
if (stylusData.pressure != -1.0) {
|
33
|
+
putMap("stylusData", stylusData.toReadableMap())
|
34
|
+
}
|
28
35
|
}
|
29
36
|
}
|
30
37
|
}
|
@@ -3,6 +3,7 @@ package com.swmansion.gesturehandler.react.eventbuilders
|
|
3
3
|
import com.facebook.react.bridge.WritableMap
|
4
4
|
import com.facebook.react.uimanager.PixelUtil
|
5
5
|
import com.swmansion.gesturehandler.core.PanGestureHandler
|
6
|
+
import com.swmansion.gesturehandler.core.StylusData
|
6
7
|
|
7
8
|
class PanGestureHandlerEventDataBuilder(handler: PanGestureHandler) : GestureHandlerEventDataBuilder<PanGestureHandler>(handler) {
|
8
9
|
private val x: Float
|
@@ -13,6 +14,7 @@ class PanGestureHandlerEventDataBuilder(handler: PanGestureHandler) : GestureHan
|
|
13
14
|
private val translationY: Float
|
14
15
|
private val velocityX: Float
|
15
16
|
private val velocityY: Float
|
17
|
+
private val stylusData: StylusData
|
16
18
|
|
17
19
|
init {
|
18
20
|
x = handler.lastRelativePositionX
|
@@ -23,6 +25,7 @@ class PanGestureHandlerEventDataBuilder(handler: PanGestureHandler) : GestureHan
|
|
23
25
|
translationY = handler.translationY
|
24
26
|
velocityX = handler.velocityX
|
25
27
|
velocityY = handler.velocityY
|
28
|
+
stylusData = handler.stylusData
|
26
29
|
}
|
27
30
|
|
28
31
|
override fun buildEventData(eventData: WritableMap) {
|
@@ -37,6 +40,10 @@ class PanGestureHandlerEventDataBuilder(handler: PanGestureHandler) : GestureHan
|
|
37
40
|
putDouble("translationY", PixelUtil.toDIPFromPixel(translationY).toDouble())
|
38
41
|
putDouble("velocityX", PixelUtil.toDIPFromPixel(velocityX).toDouble())
|
39
42
|
putDouble("velocityY", PixelUtil.toDIPFromPixel(velocityY).toDouble())
|
43
|
+
|
44
|
+
if (stylusData.pressure != -1.0) {
|
45
|
+
putMap("stylusData", stylusData.toReadableMap())
|
46
|
+
}
|
40
47
|
}
|
41
48
|
}
|
42
49
|
}
|
@@ -26,12 +26,21 @@ target_include_directories(
|
|
26
26
|
)
|
27
27
|
|
28
28
|
find_package(ReactAndroid REQUIRED CONFIG)
|
29
|
-
|
30
|
-
target_link_libraries(
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
29
|
+
if (ReactAndroid_VERSION_MINOR GREATER_EQUAL 76)
|
30
|
+
target_link_libraries(
|
31
|
+
${PACKAGE_NAME}
|
32
|
+
ReactAndroid::reactnative
|
33
|
+
ReactAndroid::jsi
|
34
|
+
)
|
35
|
+
elseif (ReactAndroid_VERSION_MINOR GREATER_EQUAL 75)
|
36
|
+
target_link_libraries(
|
37
|
+
${PACKAGE_NAME}
|
38
|
+
ReactAndroid::react_render_core
|
39
|
+
ReactAndroid::react_render_uimanager
|
40
|
+
ReactAndroid::react_render_graphics
|
41
|
+
ReactAndroid::jsi
|
42
|
+
ReactAndroid::react_nativemodule_core
|
43
|
+
)
|
44
|
+
else ()
|
45
|
+
message(FATAL_ERROR "react-native-gesture-handler on the New Architecture requires react-native 0.75 or newer.")
|
46
|
+
endif ()
|
@@ -233,10 +233,12 @@
|
|
233
233
|
recognizer.allowableMovement = [RCTConvert CGFloat:prop];
|
234
234
|
}
|
235
235
|
|
236
|
+
#if !TARGET_OS_TV
|
236
237
|
prop = config[@"numberOfPointers"];
|
237
238
|
if (prop != nil) {
|
238
239
|
recognizer.numberOfTouchesRequired = [RCTConvert CGFloat:prop];
|
239
240
|
}
|
241
|
+
#endif
|
240
242
|
}
|
241
243
|
|
242
244
|
#if !TARGET_OS_OSX
|
@@ -7,6 +7,7 @@
|
|
7
7
|
//
|
8
8
|
|
9
9
|
#import "RNPanHandler.h"
|
10
|
+
#import "RNGHStylusData.h"
|
10
11
|
|
11
12
|
#if TARGET_OS_OSX
|
12
13
|
|
@@ -31,6 +32,10 @@
|
|
31
32
|
@property (nonatomic) CGFloat failOffsetYEnd;
|
32
33
|
@property (nonatomic) CGFloat activateAfterLongPress;
|
33
34
|
|
35
|
+
#if !TARGET_OS_OSX && !TARGET_OS_TV
|
36
|
+
@property (atomic, readonly, strong) RNGHStylusData *stylusData;
|
37
|
+
#endif
|
38
|
+
|
34
39
|
- (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler;
|
35
40
|
|
36
41
|
@end
|
@@ -80,6 +85,28 @@
|
|
80
85
|
}
|
81
86
|
#endif
|
82
87
|
|
88
|
+
#if !TARGET_OS_OSX && !TARGET_OS_TV
|
89
|
+
- (void)tryUpdateStylusData:(UIEvent *)event
|
90
|
+
{
|
91
|
+
UITouch *touch = [[event allTouches] anyObject];
|
92
|
+
|
93
|
+
if (touch.type != UITouchTypePencil) {
|
94
|
+
return;
|
95
|
+
} else if (_stylusData == nil) {
|
96
|
+
_stylusData = [[RNGHStylusData alloc] init];
|
97
|
+
}
|
98
|
+
|
99
|
+
_stylusData.altitudeAngle = touch.altitudeAngle;
|
100
|
+
_stylusData.azimuthAngle = [touch azimuthAngleInView:nil];
|
101
|
+
_stylusData.pressure = touch.force / touch.maximumPossibleForce;
|
102
|
+
|
103
|
+
CGPoint tilts = ghSpherical2tilt(_stylusData.altitudeAngle, _stylusData.azimuthAngle);
|
104
|
+
|
105
|
+
_stylusData.tiltX = tilts.x;
|
106
|
+
_stylusData.tiltY = tilts.y;
|
107
|
+
}
|
108
|
+
#endif
|
109
|
+
|
83
110
|
- (void)activateAfterLongPress
|
84
111
|
{
|
85
112
|
self.state = UIGestureRecognizerStateBegan;
|
@@ -102,6 +129,8 @@
|
|
102
129
|
} else {
|
103
130
|
super.minimumNumberOfTouches = _realMinimumNumberOfTouches;
|
104
131
|
}
|
132
|
+
|
133
|
+
[self tryUpdateStylusData:event];
|
105
134
|
#endif
|
106
135
|
|
107
136
|
#if TARGET_OS_OSX
|
@@ -150,17 +179,28 @@
|
|
150
179
|
[self setTranslation:CGPointMake(0, 0) inView:self.view];
|
151
180
|
}
|
152
181
|
}
|
182
|
+
|
183
|
+
[self tryUpdateStylusData:event];
|
153
184
|
#endif
|
154
185
|
}
|
155
186
|
|
156
187
|
- (void)interactionsEnded:(NSSet *)touches withEvent:(UIEvent *)event
|
157
188
|
{
|
158
189
|
[_gestureHandler.pointerTracker touchesEnded:touches withEvent:event];
|
190
|
+
|
191
|
+
#if !TARGET_OS_TV && !TARGET_OS_OSX
|
192
|
+
[self tryUpdateStylusData:event];
|
193
|
+
#endif
|
159
194
|
}
|
160
195
|
|
161
196
|
- (void)interactionsCancelled:(NSSet *)touches withEvent:(UIEvent *)event
|
162
197
|
{
|
163
198
|
[_gestureHandler.pointerTracker touchesCancelled:touches withEvent:event];
|
199
|
+
|
200
|
+
#if !TARGET_OS_TV && !TARGET_OS_OSX
|
201
|
+
[self tryUpdateStylusData:event];
|
202
|
+
#endif
|
203
|
+
|
164
204
|
[self reset];
|
165
205
|
}
|
166
206
|
|
@@ -224,6 +264,10 @@
|
|
224
264
|
self.enabled = YES;
|
225
265
|
[super reset];
|
226
266
|
[_gestureHandler reset];
|
267
|
+
|
268
|
+
#if !TARGET_OS_TV && !TARGET_OS_OSX
|
269
|
+
_stylusData = nil;
|
270
|
+
#endif
|
227
271
|
}
|
228
272
|
|
229
273
|
- (void)updateHasCustomActivationCriteria
|
@@ -405,17 +449,23 @@
|
|
405
449
|
withTranslation:[recognizer translationInView:recognizer.view.window.contentView]
|
406
450
|
withVelocity:[recognizer velocityInView:recognizer.view.window.contentView]
|
407
451
|
withNumberOfTouches:1
|
408
|
-
withPointerType:RNGestureHandlerMouse
|
452
|
+
withPointerType:RNGestureHandlerMouse
|
453
|
+
withStylusData:nil];
|
409
454
|
}
|
410
455
|
#else
|
411
456
|
- (RNGestureHandlerEventExtraData *)eventExtraData:(UIPanGestureRecognizer *)recognizer
|
412
457
|
{
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
458
|
+
RNBetterPanGestureRecognizer *panRecognizer = (RNBetterPanGestureRecognizer *)recognizer;
|
459
|
+
|
460
|
+
return [RNGestureHandlerEventExtraData
|
461
|
+
forPan:[recognizer locationInView:recognizer.view]
|
462
|
+
withAbsolutePosition:[recognizer locationInView:recognizer.view.window]
|
463
|
+
withTranslation:[recognizer translationInView:recognizer.view.window]
|
464
|
+
withVelocity:[recognizer velocityInView:recognizer.view.window]
|
465
|
+
withNumberOfTouches:recognizer.numberOfTouches
|
466
|
+
withPointerType:_pointerType
|
467
|
+
withStylusData:[panRecognizer.stylusData toDictionary]]; // In Objective-C calling method on nil returns
|
468
|
+
// nil, therefore this line does not crash.
|
419
469
|
}
|
420
470
|
#endif
|
421
471
|
|
@@ -149,7 +149,7 @@
|
|
149
149
|
#if TARGET_OS_OSX
|
150
150
|
- (RNGestureHandlerEventExtraData *)eventExtraData:(NSRotationGestureRecognizer *)recognizer
|
151
151
|
{
|
152
|
-
return [RNGestureHandlerEventExtraData forRotation
|
152
|
+
return [RNGestureHandlerEventExtraData forRotation:-recognizer.rotation
|
153
153
|
withAnchorPoint:[recognizer locationInView:recognizer.view]
|
154
154
|
withVelocity:((RNBetterRotationRecognizer *)recognizer).velocity
|
155
155
|
withNumberOfTouches:2
|
@@ -0,0 +1,77 @@
|
|
1
|
+
//
|
2
|
+
// RNGHStylusData.h
|
3
|
+
// Pods
|
4
|
+
//
|
5
|
+
// Created by Michał Bert on 18/09/2024.
|
6
|
+
//
|
7
|
+
|
8
|
+
#ifndef RNGHStylusData_h
|
9
|
+
#define RNGHStylusData_h
|
10
|
+
|
11
|
+
@interface RNGHStylusData : NSObject
|
12
|
+
|
13
|
+
@property (atomic, assign) double tiltX;
|
14
|
+
@property (atomic, assign) double tiltY;
|
15
|
+
@property (atomic, assign) double altitudeAngle;
|
16
|
+
@property (atomic, assign) double azimuthAngle;
|
17
|
+
@property (atomic, assign) double pressure;
|
18
|
+
|
19
|
+
- (NSDictionary *)toDictionary;
|
20
|
+
|
21
|
+
@end
|
22
|
+
|
23
|
+
static CGPoint ghSpherical2tilt(double altitudeAngle, double azimuthAngle)
|
24
|
+
{
|
25
|
+
CGPoint tilts = {.x = 0.0, .y = 0.0};
|
26
|
+
|
27
|
+
const double radToDeg = 180 / M_PI;
|
28
|
+
const double eps = 0.000000001;
|
29
|
+
|
30
|
+
if (altitudeAngle < eps) {
|
31
|
+
// the pen is in the X-Y plane
|
32
|
+
if (azimuthAngle < eps || fabs(azimuthAngle - 2 * M_PI) < eps) {
|
33
|
+
// pen is on positive X axis
|
34
|
+
tilts.x = M_PI_2;
|
35
|
+
}
|
36
|
+
if (fabs(azimuthAngle - M_PI_2) < eps) {
|
37
|
+
// pen is on positive Y axis
|
38
|
+
tilts.y = M_PI_2;
|
39
|
+
}
|
40
|
+
if (fabs(azimuthAngle - M_PI) < eps) {
|
41
|
+
// pen is on negative X axis
|
42
|
+
tilts.x = -M_PI_2;
|
43
|
+
}
|
44
|
+
if (fabs(azimuthAngle - 3 * M_PI_2) < eps) {
|
45
|
+
// pen is on negative Y axis
|
46
|
+
tilts.y = -M_PI_2;
|
47
|
+
}
|
48
|
+
if (azimuthAngle > eps && fabs(azimuthAngle - M_PI_2) < eps) {
|
49
|
+
tilts.x = M_PI_2;
|
50
|
+
tilts.y = M_PI_2;
|
51
|
+
}
|
52
|
+
if (fabs(azimuthAngle - M_PI_2) > eps && fabs(azimuthAngle - M_PI) < eps) {
|
53
|
+
tilts.x = -M_PI_2;
|
54
|
+
tilts.y = M_PI_2;
|
55
|
+
}
|
56
|
+
if (azimuthAngle - M_PI > eps && fabs(azimuthAngle - 3 * M_PI_2) < eps) {
|
57
|
+
tilts.x = -M_PI_2;
|
58
|
+
tilts.y = -M_PI_2;
|
59
|
+
}
|
60
|
+
if (fabs(azimuthAngle - 3 * M_PI_2) > eps && fabs(azimuthAngle - 2 * M_PI) < eps) {
|
61
|
+
tilts.x = M_PI_2;
|
62
|
+
tilts.y = -M_PI_2;
|
63
|
+
}
|
64
|
+
} else {
|
65
|
+
const double tanAlt = tan(altitudeAngle);
|
66
|
+
|
67
|
+
tilts.x = atan(cos(azimuthAngle) / tanAlt);
|
68
|
+
tilts.y = atan(sin(azimuthAngle) / tanAlt);
|
69
|
+
}
|
70
|
+
|
71
|
+
tilts.x = round(tilts.x * radToDeg);
|
72
|
+
tilts.y = round(tilts.y * radToDeg);
|
73
|
+
|
74
|
+
return tilts;
|
75
|
+
}
|
76
|
+
|
77
|
+
#endif /* RNGHStylusData_h */
|
@@ -0,0 +1,37 @@
|
|
1
|
+
//
|
2
|
+
// RNGHStylusData.m
|
3
|
+
// DoubleConversion
|
4
|
+
//
|
5
|
+
// Created by Michał Bert on 18/09/2024.
|
6
|
+
//
|
7
|
+
|
8
|
+
#import "RNGHStylusData.h"
|
9
|
+
#import <Foundation/Foundation.h>
|
10
|
+
|
11
|
+
@implementation RNGHStylusData
|
12
|
+
|
13
|
+
- (instancetype)init
|
14
|
+
{
|
15
|
+
if (self = [super init]) {
|
16
|
+
self.tiltX = 0;
|
17
|
+
self.tiltY = 0;
|
18
|
+
self.altitudeAngle = M_PI_2;
|
19
|
+
self.azimuthAngle = 0;
|
20
|
+
self.pressure = 0;
|
21
|
+
}
|
22
|
+
|
23
|
+
return self;
|
24
|
+
}
|
25
|
+
|
26
|
+
- (NSDictionary *)toDictionary
|
27
|
+
{
|
28
|
+
return @{
|
29
|
+
@"tiltX" : @(_tiltX),
|
30
|
+
@"tiltY" : @(_tiltY),
|
31
|
+
@"altitudeAngle" : @(_altitudeAngle),
|
32
|
+
@"azimuthAngle" : @(_azimuthAngle),
|
33
|
+
@"pressure" : @(_pressure),
|
34
|
+
};
|
35
|
+
}
|
36
|
+
|
37
|
+
@end
|