Skip to content

Commit 028fbf6

Browse files
authored
[Native] Fix shouldCancelWhenOutside not tracking the view (#3942)
## Description Addresses the underlying issue of #3906 The original issue described in the above PR was caused by wrong shadow node dimensions, which were fixed by #3930. After that, the dimensions were good, but the long press was still failing. This was caused by `shouldCancelWhenOutside` checking the dimensions of the detector while the child was moved. This PR changes the logic so that the child's hitbox is checked when using the native detector. This should be enough for iOS, but on Android, further investigation is needed into whether the entire `transformedEvent` should be in the coordinate space of the detector or its child. ## Test plan See #3906 test plan
1 parent e0e3a91 commit 028fbf6

3 files changed

Lines changed: 39 additions & 18 deletions

File tree

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

Lines changed: 28 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

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

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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/apple/RNGestureHandler.mm

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -685,9 +685,16 @@ - (void)reset
685685

686686
- (BOOL)containsPointInView
687687
{
688-
CGPoint pt = [_recognizer locationInView:_recognizer.view];
689-
CGRect hitFrame = RNGHHitSlopInsetRect(_recognizer.view.bounds, _hitSlop);
690-
return CGRectContainsPoint(hitFrame, pt);
688+
RNGHUIView *viewToHitTest = _recognizer.view;
689+
690+
if (_shouldCancelWhenOutside && [self usesNativeOrVirtualDetector] && [_recognizer.view.subviews count] > 0) {
691+
viewToHitTest = _recognizer.view.subviews[0];
692+
}
693+
694+
CGPoint location = [_recognizer locationInView:viewToHitTest];
695+
CGRect hitFrame = RNGHHitSlopInsetRect(viewToHitTest.bounds, _hitSlop);
696+
697+
return CGRectContainsPoint(hitFrame, location);
691698
}
692699

693700
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer

0 commit comments

Comments
 (0)