Skip to content

Commit 072804b

Browse files
committed
Merge branch 'next' into @mbert/docs-state-manager
2 parents 8e580e4 + 028fbf6 commit 072804b

41 files changed

Lines changed: 647 additions & 154 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import android.view.MotionEvent
99
import android.view.MotionEvent.PointerCoords
1010
import android.view.MotionEvent.PointerProperties
1111
import android.view.View
12+
import androidx.core.view.isNotEmpty
1213
import com.facebook.react.bridge.Arguments
1314
import com.facebook.react.bridge.ReactContext
1415
import com.facebook.react.bridge.ReadableMap
@@ -384,18 +385,37 @@ open class GestureHandler {
384385
}
385386
}
386387

387-
x = adaptedTransformedEvent.x
388-
y = adaptedTransformedEvent.y
389388
numberOfPointers = adaptedTransformedEvent.pointerCount
390-
isWithinBounds = isWithinBounds(view, x, y)
391-
if (shouldCancelWhenOutside && !isWithinBounds) {
392-
if (state == STATE_ACTIVE) {
393-
cancel()
394-
} else if (state == STATE_BEGAN) {
389+
390+
// TODO: this is likely wrong, and the transformed event itself should be
391+
// in the coordinate system of the child view, but I'm not sure of the
392+
// consequences
393+
if (view is RNGestureHandlerDetectorView && (view as RNGestureHandlerDetectorView).isNotEmpty()) {
394+
val detector = view as RNGestureHandlerDetectorView
395+
val outPoint = PointF()
396+
GestureHandlerOrchestrator.transformPointToChildViewCoords(
397+
adaptedTransformedEvent.x,
398+
adaptedTransformedEvent.y,
399+
detector,
400+
detector.getChildAt(0),
401+
outPoint,
402+
)
403+
x = outPoint.x
404+
y = outPoint.y
405+
isWithinBounds = isWithinBounds(detector.getChildAt(0), x, y)
406+
} else {
407+
x = adaptedTransformedEvent.x
408+
y = adaptedTransformedEvent.y
409+
isWithinBounds = isWithinBounds(view, x, y)
410+
}
411+
412+
if (shouldCancelWhenOutside) {
413+
if (!isWithinBounds && (state == STATE_ACTIVE || state == STATE_BEGAN)) {
395414
fail()
415+
return
396416
}
397-
return
398417
}
418+
399419
lastAbsolutePositionX = GestureUtils.getLastPointerX(adaptedTransformedEvent, true)
400420
lastAbsolutePositionY = GestureUtils.getLastPointerY(adaptedTransformedEvent, true)
401421
lastEventOffsetX = adaptedTransformedEvent.rawX - adaptedTransformedEvent.x
@@ -595,6 +615,16 @@ open class GestureHandler {
595615
// generated faster than they can be treated by JS thread
596616
eventCoalescingKey = nextEventCoalescingKey++
597617
}
618+
619+
check(hostDetectorView != null || orchestrator != null) {
620+
"Manually handled gesture had not been assigned to any detector"
621+
}
622+
623+
if (orchestrator == null) {
624+
// If the state is set manually, the handler may not have been fully recorded by the orchestrator.
625+
hostDetectorView?.recordHandlerIfNotPresent(this)
626+
}
627+
598628
orchestrator!!.onHandlerStateChange(this, newState, oldState)
599629
onStateChange(newState, oldState)
600630
}
@@ -753,6 +783,10 @@ open class GestureHandler {
753783
protected open fun onCancel() {}
754784
protected open fun onFail() {}
755785

786+
fun recordHandlerIfNotPresent() {
787+
hostDetectorView?.recordHandlerIfNotPresent(this)
788+
}
789+
756790
private fun isButtonInConfig(clickedButton: Int): Boolean {
757791
if (mouseButton == 0) {
758792
return clickedButton == MotionEvent.BUTTON_PRIMARY

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ class GestureHandlerOrchestrator(
442442
}
443443
}
444444

445-
private fun recordHandlerIfNotPresent(handler: GestureHandler, view: View) {
445+
fun recordHandlerIfNotPresent(handler: GestureHandler, view: View?) {
446446
if (gestureHandlers.contains(handler)) {
447447
return
448448
}
@@ -750,13 +750,7 @@ class GestureHandlerOrchestrator(
750750
return isLeafOrTransparent && isTransformedTouchPointInView(coords[0], coords[1], view)
751751
}
752752

753-
private fun transformPointToChildViewCoords(
754-
x: Float,
755-
y: Float,
756-
parent: ViewGroup,
757-
child: View,
758-
outLocalPoint: PointF,
759-
) {
753+
fun transformPointToChildViewCoords(x: Float, y: Float, parent: ViewGroup, child: View, outLocalPoint: PointF) {
760754
var localX = x + parent.scrollX - child.left
761755
var localY = y + parent.scrollY - child.top
762756
val matrix = child.matrix

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@ import android.view.MotionEvent
2121
import android.view.View
2222
import android.view.View.OnClickListener
2323
import android.view.ViewGroup
24-
import android.view.ViewParent
2524
import android.view.accessibility.AccessibilityNodeInfo
2625
import androidx.core.view.children
2726
import com.facebook.react.R
2827
import com.facebook.react.module.annotations.ReactModule
2928
import com.facebook.react.uimanager.PixelUtil
29+
import com.facebook.react.uimanager.PointerEvents
30+
import com.facebook.react.uimanager.ReactPointerEventsView
3031
import com.facebook.react.uimanager.ThemedReactContext
3132
import com.facebook.react.uimanager.ViewGroupManager
3233
import com.facebook.react.uimanager.ViewManagerDelegate
@@ -132,6 +133,17 @@ class RNGestureHandlerButtonViewManager :
132133
view.isSoundEffectsEnabled = !touchSoundDisabled
133134
}
134135

136+
@ReactProp(name = ViewProps.POINTER_EVENTS)
137+
override fun setPointerEvents(view: ButtonViewGroup, pointerEvents: String?) {
138+
view.pointerEvents = when (pointerEvents) {
139+
"none" -> PointerEvents.NONE
140+
"box-none" -> PointerEvents.BOX_NONE
141+
"box-only" -> PointerEvents.BOX_ONLY
142+
"auto", null -> PointerEvents.AUTO
143+
else -> PointerEvents.AUTO
144+
}
145+
}
146+
135147
override fun onAfterUpdateTransaction(view: ButtonViewGroup) {
136148
super.onAfterUpdateTransaction(view)
137149

@@ -142,7 +154,8 @@ class RNGestureHandlerButtonViewManager :
142154

143155
class ButtonViewGroup(context: Context?) :
144156
ViewGroup(context),
145-
NativeViewGestureHandler.NativeViewGestureHandlerHook {
157+
NativeViewGestureHandler.NativeViewGestureHandlerHook,
158+
ReactPointerEventsView {
146159
// Using object because of handling null representing no value set.
147160
var rippleColor: Int? = null
148161
set(color) = withBackgroundUpdate {
@@ -200,6 +213,8 @@ class RNGestureHandlerButtonViewManager :
200213

201214
var exclusive = true
202215

216+
override var pointerEvents: PointerEvents = PointerEvents.AUTO
217+
203218
private var buttonBackgroundColor = Color.TRANSPARENT
204219
private var needBackgroundUpdate = false
205220
private var lastEventTime = -1L
@@ -497,9 +512,9 @@ class RNGestureHandlerButtonViewManager :
497512
// a parent button from playing)
498513
return if (!isChildTouched()) {
499514
if (context.isScreenReaderOn()) {
500-
findGestureHandlerRootView()?.activateNativeHandlers(this)
515+
RNGestureHandlerRootView.findGestureHandlerRootView(this)?.activateNativeHandlers(this)
501516
} else if (receivedKeyEvent) {
502-
findGestureHandlerRootView()?.activateNativeHandlers(this)
517+
RNGestureHandlerRootView.findGestureHandlerRootView(this)?.activateNativeHandlers(this)
503518
receivedKeyEvent = false
504519
}
505520

@@ -538,20 +553,6 @@ class RNGestureHandlerButtonViewManager :
538553
// by default Viewgroup would pass hotspot change events
539554
}
540555

541-
private fun findGestureHandlerRootView(): RNGestureHandlerRootView? {
542-
var parent: ViewParent? = this.parent
543-
var gestureHandlerRootView: RNGestureHandlerRootView? = null
544-
545-
while (parent != null) {
546-
if (parent is RNGestureHandlerRootView) {
547-
gestureHandlerRootView = parent
548-
}
549-
parent = parent.parent
550-
}
551-
552-
return gestureHandlerRootView
553-
}
554-
555556
companion object {
556557
var resolveOutValue = TypedValue()
557558
var touchResponder: ButtonViewGroup? = null

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.facebook.react.uimanager.events.Event
1111
import com.facebook.react.views.swiperefresh.ReactSwipeRefreshLayout
1212
import com.facebook.react.views.view.ReactViewGroup
1313
import com.swmansion.gesturehandler.core.GestureHandler
14+
import com.swmansion.gesturehandler.react.RNGestureHandlerRootView
1415

1516
class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
1617
private val reactContext: ThemedReactContext
@@ -208,6 +209,10 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
208209
}
209210
}
210211

212+
fun recordHandlerIfNotPresent(handler: GestureHandler) {
213+
RNGestureHandlerRootView.findGestureHandlerRootView(this)?.recordHandlerIfNotPresent(handler)
214+
}
215+
211216
private fun ReadableArray.mapVirtualChildren(): List<VirtualChildren> = List(size()) { i ->
212217
val child = getMap(i) ?: return@List null
213218
val handlerTags = child.getArray("handlerTags")?.toIntList().orEmpty()

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
155155
}
156156
}
157157

158+
if (newState == GestureHandler.STATE_ACTIVE || newState == GestureHandler.STATE_BEGAN) {
159+
handler.recordHandlerIfNotPresent()
160+
}
161+
158162
when (newState) {
159163
GestureHandler.STATE_ACTIVE -> handler.activate(force = true)
160164
GestureHandler.STATE_BEGAN -> handler.begin()

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ class RNGestureHandlerRootHelper(private val context: ReactContext, wrappedView:
141141
orchestrator?.activateNativeHandlersForView(view)
142142
}
143143

144+
fun recordHandlerIfNotPresent(handler: GestureHandler) {
145+
orchestrator?.recordHandlerIfNotPresent(handler, null)
146+
}
147+
144148
companion object {
145149
private const val MIN_ALPHA_FOR_TOUCH = 0.1f
146150
private fun findRootViewTag(viewGroup: ViewGroup): ViewGroup {

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import android.util.Log
55
import android.view.MotionEvent
66
import android.view.View
77
import android.view.ViewGroup
8+
import android.view.ViewParent
89
import com.facebook.react.bridge.ReactContext
910
import com.facebook.react.bridge.UiThreadUtil
1011
import com.facebook.react.common.ReactConstants
1112
import com.facebook.react.uimanager.RootView
1213
import com.facebook.react.views.view.ReactViewGroup
14+
import com.swmansion.gesturehandler.core.GestureHandler
1315

1416
class RNGestureHandlerRootView(context: Context?) : ReactViewGroup(context) {
1517
private var moduleId: Int = -1
@@ -39,6 +41,10 @@ class RNGestureHandlerRootView(context: Context?) : ReactViewGroup(context) {
3941
rootHelper?.tearDown()
4042
}
4143

44+
fun recordHandlerIfNotPresent(handler: GestureHandler) {
45+
rootHelper?.recordHandlerIfNotPresent(handler)
46+
}
47+
4248
override fun dispatchTouchEvent(event: MotionEvent) = if (rootViewEnabled && rootHelper!!.dispatchTouchEvent(event)) {
4349
true
4450
} else {
@@ -87,5 +93,19 @@ class RNGestureHandlerRootView(context: Context?) : ReactViewGroup(context) {
8793
}
8894
return false
8995
}
96+
97+
fun findGestureHandlerRootView(viewGroup: ViewGroup): RNGestureHandlerRootView? {
98+
var parent: ViewParent? = viewGroup.parent
99+
var gestureHandlerRootView: RNGestureHandlerRootView? = null
100+
101+
while (parent != null) {
102+
if (parent is RNGestureHandlerRootView) {
103+
gestureHandlerRootView = parent
104+
}
105+
parent = parent.parent
106+
}
107+
108+
return gestureHandlerRootView
109+
}
90110
}
91111
}

packages/react-native-gesture-handler/apple/Handlers/RNFlingHandler.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ - (void)touchesBegan:(NSSet<RNGHUITouch *> *)touches withEvent:(UIEvent *)event
3030
_lastPoint = [[[touches allObjects] objectAtIndex:0] locationInView:_gestureHandler.recognizer.view];
3131
[_gestureHandler reset];
3232
[super touchesBegan:touches withEvent:event];
33+
34+
if (self.state == UIGestureRecognizerStatePossible && ![self.delegate gestureRecognizerShouldBegin:self]) {
35+
self.state = UIGestureRecognizerStateFailed;
36+
return;
37+
}
38+
3339
[_gestureHandler.pointerTracker touchesBegan:touches withEvent:event];
3440

3541
// self.numberOfTouches doesn't work for this because in case than one finger is required,

packages/react-native-gesture-handler/apple/Handlers/RNLongPressHandler.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ - (void)touchesBegan:(NSSet<RNGHUITouch *> *)touches withEvent:(UIEvent *)event
8181
{
8282
[_gestureHandler setCurrentPointerType:event];
8383
[super touchesBegan:touches withEvent:event];
84+
85+
if (self.state == UIGestureRecognizerStatePossible && ![self.delegate gestureRecognizerShouldBegin:self]) {
86+
self.state = UIGestureRecognizerStateFailed;
87+
return;
88+
}
89+
8490
[_gestureHandler.pointerTracker touchesBegan:touches withEvent:event];
8591

8692
self.state = UIGestureRecognizerStatePossible;

packages/react-native-gesture-handler/apple/Handlers/RNManualHandler.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ - (id)initWithGestureHandler:(RNGestureHandler *)gestureHandler
2626

2727
- (void)interactionsBegan:(NSSet *)touches withEvent:(UIEvent *)event
2828
{
29+
if (self.state == UIGestureRecognizerStatePossible && ![self.delegate gestureRecognizerShouldBegin:self]) {
30+
self.state = UIGestureRecognizerStateFailed;
31+
return;
32+
}
33+
2934
[_gestureHandler.pointerTracker touchesBegan:touches withEvent:event];
3035

3136
if (_shouldSendBeginEvent) {

0 commit comments

Comments
 (0)