react-native-gesture-handler 2.4.0 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +3 -2
- package/android/build.gradle +28 -4
- package/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandler.kt +9 -5
- package/android/lib/src/main/java/com/swmansion/gesturehandler/GestureHandlerOrchestrator.kt +6 -1
- package/android/lib/src/main/java/com/swmansion/gesturehandler/NativeViewGestureHandler.kt +103 -22
- package/android/lib/src/main/java/com/swmansion/gesturehandler/PanGestureHandler.kt +29 -2
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +74 -84
- package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt +4 -0
- package/android/src/main/jni/Android.mk +1 -2
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNGestureHandlerButtonManagerDelegate.java +12 -9
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNGestureHandlerButtonManagerInterface.java +1 -0
- package/ios/Handlers/RNFlingHandler.m +43 -1
- package/ios/Handlers/{RNNativeViewHandler.m → RNNativeViewHandler.mm} +13 -1
- package/ios/Handlers/RNPanHandler.m +27 -0
- package/ios/RNGestureHandler.h +1 -0
- package/ios/RNGestureHandler.m +22 -4
- package/ios/RNGestureHandlerManager.mm +10 -2
- package/ios/RNGestureHandlerModule.mm +4 -1
- package/ios/RNManualActivationRecognizer.m +10 -3
- package/ios/RNRootViewGestureRecognizer.m +12 -1
- package/lib/commonjs/RNGestureHandlerModule.macos.js +81 -0
- package/lib/commonjs/RNGestureHandlerModule.macos.js.map +1 -0
- package/lib/commonjs/components/DrawerLayout.js +38 -11
- package/lib/commonjs/components/DrawerLayout.js.map +1 -1
- package/lib/commonjs/components/GestureButtons.js.map +1 -1
- package/lib/commonjs/components/touchables/GenericTouchable.js +4 -1
- package/lib/commonjs/components/touchables/GenericTouchable.js.map +1 -1
- package/lib/commonjs/fabric/RNGestureHandlerButtonNativeComponent.js.map +1 -1
- package/lib/commonjs/handlers/ForceTouchGestureHandler.js +2 -1
- package/lib/commonjs/handlers/ForceTouchGestureHandler.js.map +1 -1
- package/lib/commonjs/handlers/PanGestureHandler.js +1 -1
- package/lib/commonjs/handlers/PanGestureHandler.js.map +1 -1
- package/lib/commonjs/handlers/PressabilityDebugView.js +14 -0
- package/lib/commonjs/handlers/PressabilityDebugView.js.map +1 -0
- package/lib/commonjs/handlers/PressabilityDebugView.web.js +12 -0
- package/lib/commonjs/handlers/PressabilityDebugView.web.js.map +1 -0
- package/lib/commonjs/handlers/createHandler.js +25 -11
- package/lib/commonjs/handlers/createHandler.js.map +1 -1
- package/lib/commonjs/handlers/gestureHandlerCommon.js.map +1 -1
- package/lib/commonjs/handlers/gestures/GestureDetector.js +83 -63
- package/lib/commonjs/handlers/gestures/GestureDetector.js.map +1 -1
- package/lib/commonjs/handlers/gestures/gesture.js +13 -2
- package/lib/commonjs/handlers/gestures/gesture.js.map +1 -1
- package/lib/commonjs/handlers/gestures/gestureStateManager.js +13 -9
- package/lib/commonjs/handlers/gestures/gestureStateManager.js.map +1 -1
- package/lib/commonjs/handlers/gestures/panGesture.js +5 -0
- package/lib/commonjs/handlers/gestures/panGesture.js.map +1 -1
- package/lib/commonjs/mocks.js +2 -0
- package/lib/commonjs/mocks.js.map +1 -1
- package/lib/commonjs/utils.js +6 -3
- package/lib/commonjs/utils.js.map +1 -1
- package/lib/commonjs/web/utils.js.map +1 -1
- package/lib/module/RNGestureHandlerModule.macos.js +57 -0
- package/lib/module/RNGestureHandlerModule.macos.js.map +1 -0
- package/lib/module/components/DrawerLayout.js +38 -11
- package/lib/module/components/DrawerLayout.js.map +1 -1
- package/lib/module/components/GestureButtons.js.map +1 -1
- package/lib/module/components/touchables/GenericTouchable.js +4 -1
- package/lib/module/components/touchables/GenericTouchable.js.map +1 -1
- package/lib/module/fabric/RNGestureHandlerButtonNativeComponent.js.map +1 -1
- package/lib/module/handlers/ForceTouchGestureHandler.js +1 -1
- package/lib/module/handlers/ForceTouchGestureHandler.js.map +1 -1
- package/lib/module/handlers/PanGestureHandler.js +1 -1
- package/lib/module/handlers/PanGestureHandler.js.map +1 -1
- package/lib/module/handlers/PressabilityDebugView.js +3 -0
- package/lib/module/handlers/PressabilityDebugView.js.map +1 -0
- package/lib/module/handlers/PressabilityDebugView.web.js +5 -0
- package/lib/module/handlers/PressabilityDebugView.web.js.map +1 -0
- package/lib/module/handlers/createHandler.js +26 -12
- package/lib/module/handlers/createHandler.js.map +1 -1
- package/lib/module/handlers/gestureHandlerCommon.js.map +1 -1
- package/lib/module/handlers/gestures/GestureDetector.js +83 -63
- package/lib/module/handlers/gestures/GestureDetector.js.map +1 -1
- package/lib/module/handlers/gestures/gesture.js +13 -2
- package/lib/module/handlers/gestures/gesture.js.map +1 -1
- package/lib/module/handlers/gestures/gestureStateManager.js +13 -9
- package/lib/module/handlers/gestures/gestureStateManager.js.map +1 -1
- package/lib/module/handlers/gestures/panGesture.js +5 -0
- package/lib/module/handlers/gestures/panGesture.js.map +1 -1
- package/lib/module/mocks.js +2 -0
- package/lib/module/mocks.js.map +1 -1
- package/lib/module/utils.js +2 -1
- package/lib/module/utils.js.map +1 -1
- package/lib/module/web/utils.js.map +1 -1
- package/lib/typescript/RNGestureHandlerModule.macos.d.ts +34 -0
- package/lib/typescript/RNGestureHandlerModule.web.d.ts +1 -1
- package/lib/typescript/components/DrawerLayout.d.ts +3 -0
- package/lib/typescript/components/GestureButtons.d.ts +6 -0
- package/lib/typescript/fabric/RNGestureHandlerButtonNativeComponent.d.ts +1 -0
- package/lib/typescript/handlers/ForceTouchGestureHandler.d.ts +2 -2
- package/lib/typescript/handlers/PanGestureHandler.d.ts +2 -1
- package/lib/typescript/handlers/PressabilityDebugView.d.ts +1 -0
- package/lib/typescript/handlers/PressabilityDebugView.web.d.ts +1 -0
- package/lib/typescript/handlers/gestureHandlerCommon.d.ts +1 -0
- package/lib/typescript/handlers/gestures/GestureDetector.d.ts +2 -1
- package/lib/typescript/handlers/gestures/gesture.d.ts +3 -0
- package/lib/typescript/handlers/gestures/panGesture.d.ts +1 -0
- package/lib/typescript/mocks.d.ts +1 -0
- package/lib/typescript/web/NodeManager.d.ts +2 -2
- package/package.json +1 -1
- package/src/RNGestureHandlerModule.macos.ts +62 -0
- package/src/components/DrawerLayout.tsx +34 -10
- package/src/components/GestureButtons.tsx +7 -0
- package/src/components/touchables/GenericTouchable.tsx +1 -0
- package/src/fabric/RNGestureHandlerButtonNativeComponent.ts +1 -0
- package/src/handlers/ForceTouchGestureHandler.ts +3 -2
- package/src/handlers/PanGestureHandler.ts +2 -0
- package/src/handlers/PressabilityDebugView.tsx +2 -0
- package/src/handlers/PressabilityDebugView.web.tsx +4 -0
- package/src/handlers/{createHandler.ts → createHandler.tsx} +32 -17
- package/src/handlers/gestureHandlerCommon.ts +2 -0
- package/src/handlers/gestures/GestureDetector.tsx +107 -81
- package/src/handlers/gestures/gesture.ts +16 -0
- package/src/handlers/gestures/gestureStateManager.ts +13 -8
- package/src/handlers/gestures/panGesture.ts +5 -0
- package/src/mocks.ts +2 -0
- package/src/utils.ts +3 -1
- package/src/web/utils.ts +1 -1
- package/ios/RNGestureHandler.xcodeproj/project.xcworkspace/xcuserdata/jakubpiasecki.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/ios/RNGestureHandler.xcodeproj/xcuserdata/jakubpiasecki.xcuserdatad/xcschemes/xcschememanagement.plist +0 -19
@@ -9,6 +9,8 @@ import android.graphics.drawable.Drawable
|
|
9
9
|
import android.graphics.drawable.LayerDrawable
|
10
10
|
import android.graphics.drawable.PaintDrawable
|
11
11
|
import android.graphics.drawable.RippleDrawable
|
12
|
+
import android.graphics.drawable.ShapeDrawable
|
13
|
+
import android.graphics.drawable.shapes.RectShape
|
12
14
|
import android.os.Build
|
13
15
|
import android.util.TypedValue
|
14
16
|
import android.view.MotionEvent
|
@@ -16,7 +18,6 @@ import android.view.View
|
|
16
18
|
import android.view.View.OnClickListener
|
17
19
|
import android.view.ViewGroup
|
18
20
|
import androidx.core.view.children
|
19
|
-
import com.facebook.react.bridge.SoftAssertions
|
20
21
|
import com.facebook.react.module.annotations.ReactModule
|
21
22
|
import com.facebook.react.uimanager.PixelUtil
|
22
23
|
import com.facebook.react.uimanager.ThemedReactContext
|
@@ -77,6 +78,11 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
|
|
77
78
|
view.exclusive = exclusive
|
78
79
|
}
|
79
80
|
|
81
|
+
@ReactProp(name = "touchSoundDisabled")
|
82
|
+
override fun setTouchSoundDisabled(view: ButtonViewGroup, touchSoundDisabled: Boolean) {
|
83
|
+
view.isSoundEffectsEnabled = !touchSoundDisabled
|
84
|
+
}
|
85
|
+
|
80
86
|
override fun onAfterUpdateTransaction(view: ButtonViewGroup) {
|
81
87
|
view.updateBackground()
|
82
88
|
}
|
@@ -86,7 +92,7 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
|
|
86
92
|
}
|
87
93
|
|
88
94
|
class ButtonViewGroup(context: Context?) : ViewGroup(context),
|
89
|
-
NativeViewGestureHandler.
|
95
|
+
NativeViewGestureHandler.NativeViewGestureHandlerHook {
|
90
96
|
// Using object because of handling null representing no value set.
|
91
97
|
var rippleColor: Int? = null
|
92
98
|
set(color) = withBackgroundUpdate {
|
@@ -132,30 +138,6 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
|
|
132
138
|
_backgroundColor = color
|
133
139
|
}
|
134
140
|
|
135
|
-
private fun applyRippleEffectWhenNeeded(selectable: Drawable): Drawable {
|
136
|
-
val rippleColor = rippleColor
|
137
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && selectable is RippleDrawable) {
|
138
|
-
val states = arrayOf(intArrayOf(android.R.attr.state_enabled))
|
139
|
-
val colorStateList = if (rippleColor != null) {
|
140
|
-
val colors = intArrayOf(rippleColor)
|
141
|
-
ColorStateList(states, colors)
|
142
|
-
} else {
|
143
|
-
// if rippleColor is null, reapply the default color
|
144
|
-
context.theme.resolveAttribute(android.R.attr.colorControlHighlight, resolveOutValue, true)
|
145
|
-
val colors = intArrayOf(resolveOutValue.data)
|
146
|
-
ColorStateList(states, colors)
|
147
|
-
}
|
148
|
-
|
149
|
-
selectable.setColor(colorStateList)
|
150
|
-
}
|
151
|
-
|
152
|
-
val rippleRadius = rippleRadius
|
153
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && rippleRadius != null && selectable is RippleDrawable) {
|
154
|
-
selectable.radius = PixelUtil.toPixelFromDIP(rippleRadius.toFloat()).toInt()
|
155
|
-
}
|
156
|
-
return selectable
|
157
|
-
}
|
158
|
-
|
159
141
|
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
|
160
142
|
if (super.onInterceptTouchEvent(ev)) {
|
161
143
|
return true
|
@@ -210,49 +192,74 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
|
|
210
192
|
// reset foreground
|
211
193
|
foreground = null
|
212
194
|
}
|
195
|
+
|
196
|
+
val selectable = createSelectableDrawable()
|
197
|
+
|
198
|
+
if (borderRadius != 0f) {
|
199
|
+
// Radius-connected lines below ought to be considered
|
200
|
+
// as a temporary solution. It do not allow to set
|
201
|
+
// different radius on each corner. However, I suppose it's fairly
|
202
|
+
// fine for button-related use cases.
|
203
|
+
// Therefore it might be used as long as:
|
204
|
+
// 1. ReactViewManager is not a generic class with a possibility to handle another ViewGroup
|
205
|
+
// 2. There's no way to force native behavior of ReactViewGroup's superclass's onTouchEvent
|
206
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && selectable is RippleDrawable) {
|
207
|
+
val mask = PaintDrawable(Color.WHITE)
|
208
|
+
mask.setCornerRadius(borderRadius)
|
209
|
+
selectable.setDrawableByLayerId(android.R.id.mask, mask)
|
210
|
+
}
|
211
|
+
}
|
212
|
+
|
213
213
|
if (useDrawableOnForeground && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
214
|
-
foreground =
|
214
|
+
foreground = selectable
|
215
215
|
if (_backgroundColor != Color.TRANSPARENT) {
|
216
216
|
setBackgroundColor(_backgroundColor)
|
217
217
|
}
|
218
218
|
} else if (_backgroundColor == Color.TRANSPARENT && rippleColor == null) {
|
219
|
-
background =
|
219
|
+
background = selectable
|
220
220
|
} else {
|
221
221
|
val colorDrawable = PaintDrawable(_backgroundColor)
|
222
|
-
|
222
|
+
|
223
223
|
if (borderRadius != 0f) {
|
224
|
-
// Radius-connected lines below ought to be considered
|
225
|
-
// as a temporary solution. It do not allow to set
|
226
|
-
// different radius on each corner. However, I suppose it's fairly
|
227
|
-
// fine for button-related use cases.
|
228
|
-
// Therefore it might be used as long as:
|
229
|
-
// 1. ReactViewManager is not a generic class with a possibility to handle another ViewGroup
|
230
|
-
// 2. There's no way to force native behavior of ReactViewGroup's superclass's onTouchEvent
|
231
224
|
colorDrawable.setCornerRadius(borderRadius)
|
232
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
|
233
|
-
&& selectable is RippleDrawable) {
|
234
|
-
val mask = PaintDrawable(Color.WHITE)
|
235
|
-
mask.setCornerRadius(borderRadius)
|
236
|
-
selectable.setDrawableByLayerId(android.R.id.mask, mask)
|
237
|
-
}
|
238
225
|
}
|
239
|
-
|
226
|
+
|
240
227
|
val layerDrawable = LayerDrawable(arrayOf(colorDrawable, selectable))
|
241
228
|
background = layerDrawable
|
242
229
|
}
|
243
230
|
}
|
244
231
|
|
245
232
|
private fun createSelectableDrawable(): Drawable {
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
context.theme.resolveAttribute(attrID, resolveOutValue, true)
|
250
|
-
return if (version >= 21) {
|
251
|
-
resources.getDrawable(resolveOutValue.resourceId, context.theme)
|
252
|
-
} else {
|
233
|
+
// TODO: remove once support for RN 0.63 is dropped, since 0.64 minSdkVersion is 21
|
234
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
235
|
+
context.theme.resolveAttribute(android.R.attr.selectableItemBackground, resolveOutValue, true)
|
253
236
|
@Suppress("Deprecation")
|
254
|
-
resources.getDrawable(resolveOutValue.resourceId)
|
237
|
+
return resources.getDrawable(resolveOutValue.resourceId)
|
238
|
+
}
|
239
|
+
|
240
|
+
val states = arrayOf(intArrayOf(android.R.attr.state_enabled))
|
241
|
+
val rippleRadius = rippleRadius
|
242
|
+
val colorStateList = if (rippleColor != null) {
|
243
|
+
val colors = intArrayOf(rippleColor!!)
|
244
|
+
ColorStateList(states, colors)
|
245
|
+
} else {
|
246
|
+
// if rippleColor is null, reapply the default color
|
247
|
+
context.theme.resolveAttribute(android.R.attr.colorControlHighlight, resolveOutValue, true)
|
248
|
+
val colors = intArrayOf(resolveOutValue.data)
|
249
|
+
ColorStateList(states, colors)
|
250
|
+
}
|
251
|
+
|
252
|
+
val drawable = RippleDrawable(
|
253
|
+
colorStateList,
|
254
|
+
null,
|
255
|
+
if (useBorderlessDrawable) null else ShapeDrawable(RectShape())
|
256
|
+
)
|
257
|
+
|
258
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && rippleRadius != null) {
|
259
|
+
drawable.radius = PixelUtil.toPixelFromDIP(rippleRadius.toFloat()).toInt()
|
255
260
|
}
|
261
|
+
|
262
|
+
return drawable
|
256
263
|
}
|
257
264
|
|
258
265
|
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
|
@@ -265,7 +272,7 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
|
|
265
272
|
}
|
266
273
|
}
|
267
274
|
|
268
|
-
override fun
|
275
|
+
override fun canBegin(): Boolean {
|
269
276
|
val isResponder = tryGrabbingResponder()
|
270
277
|
if (isResponder) {
|
271
278
|
isTouched = true
|
@@ -273,11 +280,6 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
|
|
273
280
|
return isResponder
|
274
281
|
}
|
275
282
|
|
276
|
-
override fun afterGestureEnd() {
|
277
|
-
tryFreeingResponder()
|
278
|
-
isTouched = false
|
279
|
-
}
|
280
|
-
|
281
283
|
private fun tryGrabbingResponder(): Boolean {
|
282
284
|
if (isChildTouched()) {
|
283
285
|
return false
|
@@ -294,24 +296,30 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
|
|
294
296
|
}
|
295
297
|
}
|
296
298
|
|
297
|
-
private fun tryFreeingResponder() {
|
298
|
-
if (responder === this) {
|
299
|
-
responder = null
|
300
|
-
}
|
301
|
-
}
|
302
|
-
|
303
299
|
private fun isChildTouched(children: Sequence<View> = this.children): Boolean {
|
304
300
|
for (child in children) {
|
305
301
|
if (child is ButtonViewGroup && (child.isTouched || child.isPressed)) {
|
306
302
|
return true
|
307
303
|
} else if (child is ViewGroup) {
|
308
|
-
|
304
|
+
if (isChildTouched(child.children)) {
|
305
|
+
return true
|
306
|
+
}
|
309
307
|
}
|
310
308
|
}
|
311
309
|
|
312
310
|
return false
|
313
311
|
}
|
314
312
|
|
313
|
+
override fun performClick(): Boolean {
|
314
|
+
// don't preform click when a child button is pressed (mainly to prevent sound effect of
|
315
|
+
// a parent button from playing)
|
316
|
+
return if (!isChildTouched()) {
|
317
|
+
super.performClick()
|
318
|
+
} else {
|
319
|
+
false
|
320
|
+
}
|
321
|
+
}
|
322
|
+
|
315
323
|
override fun setPressed(pressed: Boolean) {
|
316
324
|
// there is a possibility of this method being called before NativeViewGestureHandler has
|
317
325
|
// opportunity to call canStart, in that case we need to grab responder in case the gesture
|
@@ -329,12 +337,13 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
|
|
329
337
|
if (!pressed || responder === this || canBePressedAlongsideOther) {
|
330
338
|
// we set pressed state only for current responder or any non-exclusive button when responder
|
331
339
|
// is null or non-exclusive, assuming it doesn't have pressed children
|
332
|
-
super.setPressed(pressed)
|
333
340
|
isTouched = pressed
|
341
|
+
super.setPressed(pressed)
|
334
342
|
}
|
335
343
|
if (!pressed && responder === this) {
|
336
344
|
// if the responder is no longer pressed we release button responder
|
337
345
|
responder = null
|
346
|
+
isTouched = false
|
338
347
|
}
|
339
348
|
}
|
340
349
|
|
@@ -344,28 +353,9 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
|
|
344
353
|
}
|
345
354
|
|
346
355
|
companion object {
|
347
|
-
const val SELECTABLE_ITEM_BACKGROUND = "selectableItemBackground"
|
348
|
-
const val SELECTABLE_ITEM_BACKGROUND_BORDERLESS = "selectableItemBackgroundBorderless"
|
349
|
-
|
350
356
|
var resolveOutValue = TypedValue()
|
351
357
|
var responder: ButtonViewGroup? = null
|
352
358
|
var dummyClickListener = OnClickListener { }
|
353
|
-
|
354
|
-
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
355
|
-
private fun getAttrId(context: Context, attr: String): Int {
|
356
|
-
SoftAssertions.assertNotNull(attr)
|
357
|
-
return when (attr) {
|
358
|
-
SELECTABLE_ITEM_BACKGROUND -> {
|
359
|
-
android.R.attr.selectableItemBackground
|
360
|
-
}
|
361
|
-
SELECTABLE_ITEM_BACKGROUND_BORDERLESS -> {
|
362
|
-
android.R.attr.selectableItemBackgroundBorderless
|
363
|
-
}
|
364
|
-
else -> {
|
365
|
-
context.resources.getIdentifier(attr, "attr", "android")
|
366
|
-
}
|
367
|
-
}
|
368
|
-
}
|
369
359
|
}
|
370
360
|
}
|
371
361
|
|
@@ -224,6 +224,9 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?)
|
|
224
224
|
if (config.hasKey(KEY_PAN_AVG_TOUCHES)) {
|
225
225
|
handler.setAverageTouches(config.getBoolean(KEY_PAN_AVG_TOUCHES))
|
226
226
|
}
|
227
|
+
if (config.hasKey(KEY_PAN_ACTIVATE_AFTER_LONG_PRESS)) {
|
228
|
+
handler.setActivateAfterLongPress(config.getInt(KEY_PAN_ACTIVATE_AFTER_LONG_PRESS).toLong())
|
229
|
+
}
|
227
230
|
}
|
228
231
|
|
229
232
|
override fun extractEventData(handler: PanGestureHandler, eventData: WritableMap) {
|
@@ -656,6 +659,7 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?)
|
|
656
659
|
private const val KEY_PAN_MIN_POINTERS = "minPointers"
|
657
660
|
private const val KEY_PAN_MAX_POINTERS = "maxPointers"
|
658
661
|
private const val KEY_PAN_AVG_TOUCHES = "avgTouches"
|
662
|
+
private const val KEY_PAN_ACTIVATE_AFTER_LONG_PRESS = "activateAfterLongPress"
|
659
663
|
private const val KEY_NUMBER_OF_POINTERS = "numberOfPointers"
|
660
664
|
private const val KEY_DIRECTION = "direction"
|
661
665
|
|
@@ -28,7 +28,7 @@ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) $(GENERATED_SRC_DIR)/codegen/jni
|
|
28
28
|
LOCAL_SHARED_LIBRARIES := libjsi \
|
29
29
|
libfbjni \
|
30
30
|
libglog \
|
31
|
-
|
31
|
+
libfolly_runtime \
|
32
32
|
libyoga \
|
33
33
|
libreact_nativemodule_core \
|
34
34
|
libturbomodulejsijni \
|
@@ -36,7 +36,6 @@ LOCAL_SHARED_LIBRARIES := libjsi \
|
|
36
36
|
libreact_render_core \
|
37
37
|
libreact_render_graphics \
|
38
38
|
libfabricjni \
|
39
|
-
libfolly_futures \
|
40
39
|
libreact_debug \
|
41
40
|
libreact_render_componentregistry \
|
42
41
|
libreact_render_debug \
|
@@ -1,11 +1,11 @@
|
|
1
1
|
/**
|
2
|
-
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
3
|
-
*
|
4
|
-
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
5
|
-
* once the code is regenerated.
|
6
|
-
*
|
7
|
-
* @generated by codegen project: GeneratePropsJavaDelegate.js
|
8
|
-
*/
|
2
|
+
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
3
|
+
*
|
4
|
+
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
5
|
+
* once the code is regenerated.
|
6
|
+
*
|
7
|
+
* @generated by codegen project: GeneratePropsJavaDelegate.js
|
8
|
+
*/
|
9
9
|
|
10
10
|
package com.facebook.react.viewmanagers;
|
11
11
|
|
@@ -23,7 +23,7 @@ public class RNGestureHandlerButtonManagerDelegate<T extends View, U extends Bas
|
|
23
23
|
public void setProperty(T view, String propName, @Nullable Object value) {
|
24
24
|
switch (propName) {
|
25
25
|
case "exclusive":
|
26
|
-
mViewManager.setExclusive(view, value == null ?
|
26
|
+
mViewManager.setExclusive(view, value == null ? true : (boolean) value);
|
27
27
|
break;
|
28
28
|
case "foreground":
|
29
29
|
mViewManager.setForeground(view, value == null ? false : (boolean) value);
|
@@ -32,7 +32,7 @@ public class RNGestureHandlerButtonManagerDelegate<T extends View, U extends Bas
|
|
32
32
|
mViewManager.setBorderless(view, value == null ? false : (boolean) value);
|
33
33
|
break;
|
34
34
|
case "enabled":
|
35
|
-
mViewManager.setEnabled(view, value == null ?
|
35
|
+
mViewManager.setEnabled(view, value == null ? true : (boolean) value);
|
36
36
|
break;
|
37
37
|
case "rippleColor":
|
38
38
|
mViewManager.setRippleColor(view, ColorPropConverter.getColor(value, view.getContext()));
|
@@ -40,6 +40,9 @@ public class RNGestureHandlerButtonManagerDelegate<T extends View, U extends Bas
|
|
40
40
|
case "rippleRadius":
|
41
41
|
mViewManager.setRippleRadius(view, value == null ? 0 : ((Double) value).intValue());
|
42
42
|
break;
|
43
|
+
case "touchSoundDisabled":
|
44
|
+
mViewManager.setTouchSoundDisabled(view, value == null ? false : (boolean) value);
|
45
|
+
break;
|
43
46
|
default:
|
44
47
|
super.setProperty(view, propName, value);
|
45
48
|
}
|
@@ -19,4 +19,5 @@ public interface RNGestureHandlerButtonManagerInterface<T extends View> {
|
|
19
19
|
void setEnabled(T view, boolean value);
|
20
20
|
void setRippleColor(T view, @Nullable Integer value);
|
21
21
|
void setRippleRadius(T view, int value);
|
22
|
+
void setTouchSoundDisabled(T view, boolean value);
|
22
23
|
}
|
@@ -8,38 +8,54 @@
|
|
8
8
|
|
9
9
|
@implementation RNBetterSwipeGestureRecognizer {
|
10
10
|
__weak RNGestureHandler* _gestureHandler;
|
11
|
+
CGPoint _lastPoint; // location of the most recently updated touch, relative to the view
|
12
|
+
bool _hasBegan; // whether the `BEGAN` event has been sent
|
11
13
|
}
|
12
14
|
|
13
15
|
- (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler
|
14
16
|
{
|
15
17
|
if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:)])) {
|
16
18
|
_gestureHandler = gestureHandler;
|
19
|
+
_lastPoint = CGPointZero;
|
20
|
+
_hasBegan = NO;
|
17
21
|
}
|
18
22
|
return self;
|
19
23
|
}
|
20
24
|
|
21
25
|
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
22
26
|
{
|
27
|
+
_lastPoint = [[[touches allObjects] objectAtIndex:0] locationInView:_gestureHandler.recognizer.view];
|
23
28
|
[_gestureHandler reset];
|
24
|
-
[self triggerAction];
|
25
29
|
[super touchesBegan:touches withEvent:event];
|
30
|
+
|
31
|
+
// self.numberOfTouches doesn't work for this because in case than one finger is required,
|
32
|
+
// when holding one finger on the screen and tapping with the second one, numberOfTouches is equal
|
33
|
+
// to 2 only for the first tap but 1 for all the following ones
|
34
|
+
if (!_hasBegan) {
|
35
|
+
[self triggerAction];
|
36
|
+
_hasBegan = YES;
|
37
|
+
}
|
38
|
+
|
26
39
|
[_gestureHandler.pointerTracker touchesBegan:touches withEvent:event];
|
27
40
|
}
|
28
41
|
|
29
42
|
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
30
43
|
{
|
44
|
+
_lastPoint = [[[touches allObjects] objectAtIndex:0] locationInView:_gestureHandler.recognizer.view];
|
31
45
|
[super touchesMoved:touches withEvent:event];
|
32
46
|
[_gestureHandler.pointerTracker touchesMoved:touches withEvent:event];
|
33
47
|
}
|
34
48
|
|
35
49
|
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
36
50
|
{
|
51
|
+
_lastPoint = [[[touches allObjects] objectAtIndex:0] locationInView:_gestureHandler.recognizer.view];
|
37
52
|
[super touchesEnded:touches withEvent:event];
|
38
53
|
[_gestureHandler.pointerTracker touchesEnded:touches withEvent:event];
|
39
54
|
}
|
40
55
|
|
41
56
|
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
42
57
|
{
|
58
|
+
_lastPoint = [[[touches allObjects] objectAtIndex:0] locationInView:_gestureHandler.recognizer.view];
|
43
59
|
[super touchesCancelled:touches withEvent:event];
|
44
60
|
[_gestureHandler.pointerTracker touchesCancelled:touches withEvent:event];
|
45
61
|
}
|
@@ -53,9 +69,17 @@
|
|
53
69
|
{
|
54
70
|
[self triggerAction];
|
55
71
|
[_gestureHandler.pointerTracker reset];
|
72
|
+
_hasBegan = NO;
|
56
73
|
[super reset];
|
57
74
|
}
|
58
75
|
|
76
|
+
- (CGPoint)getLastLocation {
|
77
|
+
// I think keeping the location of only one touch is enough since it would be used to determine the direction
|
78
|
+
// of the movement, and if it's wrong the recognizer fails anyway.
|
79
|
+
// In case the location of all touches is required, touch events are the way to go
|
80
|
+
return _lastPoint;
|
81
|
+
}
|
82
|
+
|
59
83
|
@end
|
60
84
|
|
61
85
|
@implementation RNFlingGestureHandler
|
@@ -104,5 +128,23 @@
|
|
104
128
|
return shouldBegin;
|
105
129
|
}
|
106
130
|
|
131
|
+
- (RNGestureHandlerEventExtraData *)eventExtraData:(id)_recognizer
|
132
|
+
{
|
133
|
+
// For some weird reason [recognizer locationInView:recognizer.view.window] returns (0, 0).
|
134
|
+
// To calculate the correct absolute position, first calculate the absolute position of the
|
135
|
+
// view inside the root view controller (https://stackoverflow.com/a/7448573) and then
|
136
|
+
// add the relative touch position to it.
|
137
|
+
|
138
|
+
RNBetterSwipeGestureRecognizer *recognizer = (RNBetterSwipeGestureRecognizer *)_recognizer;
|
139
|
+
|
140
|
+
CGPoint viewAbsolutePosition = [recognizer.view convertPoint:recognizer.view.bounds.origin toView:[UIApplication sharedApplication].keyWindow.rootViewController.view];
|
141
|
+
CGPoint locationInView = [recognizer getLastLocation];
|
142
|
+
|
143
|
+
return [RNGestureHandlerEventExtraData
|
144
|
+
forPosition:locationInView
|
145
|
+
withAbsolutePosition:CGPointMake(viewAbsolutePosition.x + locationInView.x, viewAbsolutePosition.y + locationInView.y)
|
146
|
+
withNumberOfTouches:recognizer.numberOfTouches];
|
147
|
+
}
|
148
|
+
|
107
149
|
@end
|
108
150
|
|
@@ -11,9 +11,14 @@
|
|
11
11
|
#import <UIKit/UIGestureRecognizerSubclass.h>
|
12
12
|
|
13
13
|
#import <React/RCTConvert.h>
|
14
|
-
#import <React/RCTScrollView.h>
|
15
14
|
#import <React/UIView+React.h>
|
16
15
|
|
16
|
+
#ifdef RN_FABRIC_ENABLED
|
17
|
+
#import <React/RCTScrollViewComponentView.h>
|
18
|
+
#else
|
19
|
+
#import <React/RCTScrollView.h>
|
20
|
+
#endif // RN_FABRIC_ENABLED
|
21
|
+
|
17
22
|
#pragma mark RNDummyGestureRecognizer
|
18
23
|
|
19
24
|
@implementation RNDummyGestureRecognizer {
|
@@ -101,6 +106,12 @@
|
|
101
106
|
// We can restore default scrollview behaviour to delay touches to scrollview's children
|
102
107
|
// because gesture handler system can handle cancellation of scroll recognizer when JS responder
|
103
108
|
// is set
|
109
|
+
#ifdef RN_FABRIC_ENABLED
|
110
|
+
if ([view isKindOfClass:[RCTScrollViewComponentView class]]) {
|
111
|
+
UIScrollView *scrollView = ((RCTScrollViewComponentView *)view).scrollView;
|
112
|
+
scrollView.delaysContentTouches = YES;
|
113
|
+
}
|
114
|
+
#else
|
104
115
|
if ([view isKindOfClass:[RCTScrollView class]]) {
|
105
116
|
// This part of the code is coupled with RN implementation of ScrollView native wrapper and
|
106
117
|
// we expect for RCTScrollView component to contain a subclass of UIScrollview as the only
|
@@ -108,6 +119,7 @@
|
|
108
119
|
UIScrollView *scrollView = [view.subviews objectAtIndex:0];
|
109
120
|
scrollView.delaysContentTouches = YES;
|
110
121
|
}
|
122
|
+
#endif // RN_FABRIC_ENABLED
|
111
123
|
}
|
112
124
|
|
113
125
|
- (void)handleTouchDown:(UIView *)sender forEvent:(UIEvent *)event
|
@@ -24,6 +24,7 @@
|
|
24
24
|
@property (nonatomic) CGFloat activeOffsetYEnd;
|
25
25
|
@property (nonatomic) CGFloat failOffsetYStart;
|
26
26
|
@property (nonatomic) CGFloat failOffsetYEnd;
|
27
|
+
@property (nonatomic) CGFloat activateAfterLongPress;
|
27
28
|
|
28
29
|
|
29
30
|
- (id)initWithGestureHandler:(RNGestureHandler*)gestureHandler;
|
@@ -53,6 +54,7 @@
|
|
53
54
|
_activeOffsetYEnd = NAN;
|
54
55
|
_failOffsetYStart = NAN;
|
55
56
|
_failOffsetYEnd = NAN;
|
57
|
+
_activateAfterLongPress = NAN;
|
56
58
|
_hasCustomActivationCriteria = NO;
|
57
59
|
#if !TARGET_OS_TV
|
58
60
|
_realMinimumNumberOfTouches = self.minimumNumberOfTouches;
|
@@ -71,6 +73,13 @@
|
|
71
73
|
_realMinimumNumberOfTouches = minimumNumberOfTouches;
|
72
74
|
}
|
73
75
|
|
76
|
+
- (void)activateAfterLongPress
|
77
|
+
{
|
78
|
+
self.state = UIGestureRecognizerStateBegan;
|
79
|
+
// Send event in ACTIVE state because UIGestureRecognizerStateBegan is mapped to RNGestureHandlerStateBegan
|
80
|
+
[_gestureHandler handleGesture:self inState:RNGestureHandlerStateActive];
|
81
|
+
}
|
82
|
+
|
74
83
|
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
75
84
|
{
|
76
85
|
if ([self numberOfTouches] == 0) {
|
@@ -89,6 +98,10 @@
|
|
89
98
|
[super touchesBegan:touches withEvent:event];
|
90
99
|
[self triggerAction];
|
91
100
|
[_gestureHandler.pointerTracker touchesBegan:touches withEvent:event];
|
101
|
+
|
102
|
+
if (!isnan(_activateAfterLongPress)) {
|
103
|
+
[self performSelector:@selector(activateAfterLongPress) withObject:nil afterDelay:_activateAfterLongPress];
|
104
|
+
}
|
92
105
|
}
|
93
106
|
|
94
107
|
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
@@ -140,6 +153,7 @@
|
|
140
153
|
{
|
141
154
|
[self triggerAction];
|
142
155
|
[_gestureHandler.pointerTracker reset];
|
156
|
+
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(activateAfterLongPress) object:nil];
|
143
157
|
self.enabled = YES;
|
144
158
|
[super reset];
|
145
159
|
}
|
@@ -155,6 +169,12 @@
|
|
155
169
|
- (BOOL)shouldFailUnderCustomCriteria
|
156
170
|
{
|
157
171
|
CGPoint trans = [self translationInView:self.view.window];
|
172
|
+
// Apple docs say that 10 units is the default allowable movement for UILongPressGestureRecognizer
|
173
|
+
if (!isnan(_activateAfterLongPress) && trans.x * trans.x + trans.y * trans.y > 100) {
|
174
|
+
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(activateAfterLongPress) object:nil];
|
175
|
+
return YES;
|
176
|
+
}
|
177
|
+
|
158
178
|
if (!isnan(_failOffsetXStart) && trans.x < _failOffsetXStart) {
|
159
179
|
return YES;
|
160
180
|
}
|
@@ -242,6 +262,7 @@
|
|
242
262
|
#endif
|
243
263
|
recognizer.minDistSq = NAN;
|
244
264
|
recognizer.minVelocitySq = NAN;
|
265
|
+
recognizer.activateAfterLongPress = NAN;
|
245
266
|
}
|
246
267
|
|
247
268
|
- (void)configure:(NSDictionary *)config
|
@@ -283,6 +304,12 @@
|
|
283
304
|
CGFloat velocity = [RCTConvert CGFloat:prop];
|
284
305
|
recognizer.minVelocitySq = velocity * velocity;
|
285
306
|
}
|
307
|
+
|
308
|
+
prop = config[@"activateAfterLongPress"];
|
309
|
+
if (prop != nil) {
|
310
|
+
recognizer.activateAfterLongPress = [RCTConvert CGFloat:prop] / 1000.0;
|
311
|
+
recognizer.minDistSq = MAX(100, recognizer.minDistSq);
|
312
|
+
}
|
286
313
|
[recognizer updateHasCustomActivationCriteria];
|
287
314
|
}
|
288
315
|
|
package/ios/RNGestureHandler.h
CHANGED
@@ -65,6 +65,7 @@ if (value != nil) { recognizer.prop = [RCTConvert type:value]; }\
|
|
65
65
|
- (void)resetConfig NS_REQUIRES_SUPER;
|
66
66
|
- (void)configure:(nullable NSDictionary *)config NS_REQUIRES_SUPER;
|
67
67
|
- (void)handleGesture:(nonnull id)recognizer;
|
68
|
+
- (void)handleGesture:(nonnull id)recognizer inState:(RNGestureHandlerState)state;
|
68
69
|
- (BOOL)containsPointInView;
|
69
70
|
- (RNGestureHandlerState)state;
|
70
71
|
- (nullable RNGestureHandlerEventExtraData *)eventExtraData:(nonnull id)recognizer;
|
package/ios/RNGestureHandler.m
CHANGED
@@ -203,6 +203,12 @@ static NSHashTable<RNGestureHandler *> *allGestureHandlers;
|
|
203
203
|
}
|
204
204
|
|
205
205
|
_state = [self recognizerState];
|
206
|
+
[self handleGesture:recognizer inState:_state];
|
207
|
+
}
|
208
|
+
|
209
|
+
- (void)handleGesture:(UIGestureRecognizer *)recognizer inState:(RNGestureHandlerState)state
|
210
|
+
{
|
211
|
+
_state = state;
|
206
212
|
RNGestureHandlerEventExtraData *eventData = [self eventExtraData:recognizer];
|
207
213
|
[self sendEventsInState:self.state forViewWithTag:recognizer.view.reactTag withExtraData:eventData];
|
208
214
|
}
|
@@ -212,6 +218,11 @@ static NSHashTable<RNGestureHandler *> *allGestureHandlers;
|
|
212
218
|
withExtraData:(RNGestureHandlerEventExtraData *)extraData
|
213
219
|
{
|
214
220
|
if (state != _lastState) {
|
221
|
+
// don't send change events from END to FAILED or CANCELLED, this may happen when gesture is ended in `onTouchesUp` callback
|
222
|
+
if (_lastState == RNGestureHandlerStateEnd && (state == RNGestureHandlerStateFailed || state == RNGestureHandlerStateCancelled)) {
|
223
|
+
return;
|
224
|
+
}
|
225
|
+
|
215
226
|
if (state == RNGestureHandlerStateActive) {
|
216
227
|
// Generate a unique coalescing-key each time the gesture-handler becomes active. All events will have
|
217
228
|
// the same coalescing-key allowing RCTEventDispatcher to coalesce RNGestureHandlerEvents when events are
|
@@ -219,7 +230,7 @@ static NSHashTable<RNGestureHandler *> *allGestureHandlers;
|
|
219
230
|
static uint16_t nextEventCoalescingKey = 0;
|
220
231
|
self->_eventCoalescingKey = nextEventCoalescingKey++;
|
221
232
|
|
222
|
-
} else if (state == RNGestureHandlerStateEnd && _lastState != RNGestureHandlerStateActive) {
|
233
|
+
} else if (state == RNGestureHandlerStateEnd && _lastState != RNGestureHandlerStateActive && !_manualActivation) {
|
223
234
|
id event = [[RNGestureHandlerStateChange alloc] initWithReactTag:reactTag
|
224
235
|
handlerTag:_tag
|
225
236
|
state:RNGestureHandlerStateActive
|
@@ -390,14 +401,21 @@ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherG
|
|
390
401
|
if (_recognizer.state == UIGestureRecognizerStateBegan && _recognizer.state == UIGestureRecognizerStatePossible) {
|
391
402
|
return YES;
|
392
403
|
}
|
393
|
-
|
394
|
-
|
395
|
-
|
404
|
+
|
405
|
+
RNGestureHandler *handler = [RNGestureHandler findGestureHandlerByRecognizer:otherGestureRecognizer];
|
406
|
+
if (handler != nil) {
|
407
|
+
if ([_simultaneousHandlers count]) {
|
396
408
|
for (NSNumber *handlerTag in _simultaneousHandlers) {
|
397
409
|
if ([handler.tag isEqual:handlerTag]) {
|
398
410
|
return YES;
|
399
411
|
}
|
400
412
|
}
|
413
|
+
} else if (handler->_simultaneousHandlers) {
|
414
|
+
for (NSNumber *handlerTag in handler->_simultaneousHandlers) {
|
415
|
+
if ([self.tag isEqual:handlerTag]) {
|
416
|
+
return YES;
|
417
|
+
}
|
418
|
+
}
|
401
419
|
}
|
402
420
|
}
|
403
421
|
return NO;
|
@@ -4,7 +4,6 @@
|
|
4
4
|
#import <React/RCTViewManager.h>
|
5
5
|
#import <React/RCTComponent.h>
|
6
6
|
#import <React/RCTRootView.h>
|
7
|
-
#import <React/RCTTouchHandler.h>
|
8
7
|
#import <React/RCTUIManager.h>
|
9
8
|
#import <React/RCTEventDispatcher.h>
|
10
9
|
|
@@ -22,6 +21,9 @@
|
|
22
21
|
|
23
22
|
#ifdef RN_FABRIC_ENABLED
|
24
23
|
#import <React/RCTViewComponentView.h>
|
24
|
+
#import <React/RCTSurfaceTouchHandler.h>
|
25
|
+
#else
|
26
|
+
#import <React/RCTTouchHandler.h>
|
25
27
|
#endif // RN_FABRIC_ENABLED
|
26
28
|
|
27
29
|
#import "Handlers/RNPanHandler.h"
|
@@ -211,8 +213,14 @@
|
|
211
213
|
// Once the upstream fix lands the line below along with this comment can be removed
|
212
214
|
if ([gestureRecognizer.view isKindOfClass:[UIScrollView class]]) return;
|
213
215
|
|
216
|
+
#ifdef RN_FABRIC_ENABLED
|
217
|
+
RCTSurfaceTouchHandler *touchHandler = [viewWithTouchHandler performSelector:@selector(touchHandler)];
|
218
|
+
#else
|
214
219
|
RCTTouchHandler *touchHandler = [viewWithTouchHandler performSelector:@selector(touchHandler)];
|
215
|
-
|
220
|
+
#endif
|
221
|
+
[touchHandler setEnabled:NO];
|
222
|
+
[touchHandler setEnabled:YES];
|
223
|
+
|
216
224
|
}
|
217
225
|
|
218
226
|
#pragma mark Events
|