Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import android.view.MotionEvent
import android.view.MotionEvent.PointerCoords
import android.view.MotionEvent.PointerProperties
import android.view.View
import androidx.core.view.isNotEmpty
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.ReadableMap
Expand Down Expand Up @@ -48,6 +47,26 @@ open class GestureHandler {
}
}

/**
* The view whose coordinate space should be used when reporting event positions to JS.
*
* Handlers attached via the V3 NativeDetector are registered against the DetectorView wrapper,
* which never carries user-applied transforms — those live on its child. When the detector has
* exactly one child we descend into it so reported coordinates match the visible (transformed)
* view, the same coordinate space V2 and the V3 VirtualGestureDetector report in. With
* multiple children there is no JS-side way to disambiguate which child caught the pointer,
* so we keep the detector itself as the reference frame.
*/
val coordinateView: View?
get() {
val v = view
Comment thread
m-bert marked this conversation as resolved.
return if (v is RNGestureHandlerDetectorView && v.childCount == 1) {
v.getChildAt(0)
} else {
v
}
}
Comment thread
j-piasecki marked this conversation as resolved.

var state = STATE_UNDETERMINED
private set
var x = 0f
Expand Down Expand Up @@ -387,42 +406,13 @@ open class GestureHandler {

numberOfPointers = adaptedTransformedEvent.pointerCount

// TODO: this is likely wrong, and the transformed event itself should be
// in the coordinate system of the child view, but I'm not sure of the
// consequences
val detectorView = hostDetectorView
if (detectorView != null && view == detectorView && detectorView.isNotEmpty()) {
val outPoint = PointF()
var foundChild = false

for (i in 0 until detectorView.childCount) {
val child = detectorView.getChildAt(i)
GestureHandlerOrchestrator.transformPointToChildViewCoords(
adaptedTransformedEvent.x,
adaptedTransformedEvent.y,
detectorView,
child,
outPoint,
)
if (isWithinBounds(child, outPoint.x, outPoint.y)) {
x = outPoint.x
y = outPoint.y
isWithinBounds = true
foundChild = true
break
}
}

if (!foundChild) {
x = adaptedTransformedEvent.x
y = adaptedTransformedEvent.y
isWithinBounds = false
}
} else {
x = adaptedTransformedEvent.x
y = adaptedTransformedEvent.y
isWithinBounds = isWithinBounds(view, x, y)
}
x = adaptedTransformedEvent.x
y = adaptedTransformedEvent.y
// The orchestrator transforms incoming events into the coordinate space of the detector's
// child (when the handler is attached to a NativeDetector wrapper), so bounds-checking must
// also use that child rather than the wrapper, otherwise hit-testing would ignore the user's
// transforms applied to the visible view.
isWithinBounds = isWithinBounds(coordinateView, x, y)

if (shouldCancelWhenOutside) {
if (!isWithinBounds && (state == STATE_ACTIVE || state == STATE_BEGAN)) {
Expand Down Expand Up @@ -872,7 +862,7 @@ open class GestureHandler {
* This method modifies and transforms the received point.
*/
protected fun transformPoint(point: PointF): PointF =
orchestrator?.transformPointToViewCoords(this.view, point) ?: run {
orchestrator?.transformPointToViewCoords(coordinateView, point) ?: run {
point.x = Float.NaN
point.y = Float.NaN
point
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ class GestureHandlerOrchestrator(
}

val action = sourceEvent.actionMasked
val event = transformEventToViewCoords(handler.view, MotionEvent.obtain(sourceEvent))
val event = transformEventToViewCoords(handler.coordinateView, MotionEvent.obtain(sourceEvent))

if (handler.needsPointerData) {
handler.updatePointerData(event, sourceEvent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ - (void)updateConfig:(NSDictionary *)config
- (RNGestureHandlerEventExtraData *)eventExtraData:(RNForceTouchGestureRecognizer *)recognizer
{
return [RNGestureHandlerEventExtraData forForce:recognizer.force
forPosition:[recognizer locationInView:recognizer.view]
forPosition:[recognizer locationInView:self.coordinateView]
withAbsolutePosition:[recognizer locationInView:recognizer.view.window]
withNumberOfTouches:recognizer.numberOfTouches
withPointerType:_pointerType];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ - (void)setCurrentPointerType:(RNGestureHandlerPointerType)pointerType

- (RNGestureHandlerEventExtraData *)eventExtraData:(UIGestureRecognizer *)recognizer
{
return [RNGestureHandlerEventExtraData forPosition:[recognizer locationInView:recognizer.view]
return [RNGestureHandlerEventExtraData forPosition:[recognizer locationInView:self.coordinateView]
withAbsolutePosition:[recognizer locationInView:recognizer.view.window]
withPointerType:_pointerType];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer

- (RNGestureHandlerEventExtraData *)eventExtraData:(UIGestureRecognizer *)recognizer
{
return [RNGestureHandlerEventExtraData forPosition:[recognizer locationInView:recognizer.view]
return [RNGestureHandlerEventExtraData forPosition:[recognizer locationInView:self.coordinateView]
withAbsolutePosition:[recognizer locationInView:recognizer.view.window]
withNumberOfTouches:recognizer.numberOfTouches
withDuration:[(RNBetterLongPressGestureRecognizer *)recognizer getDuration]
Expand All @@ -298,7 +298,7 @@ - (RNGestureHandlerEventExtraData *)eventExtraData:(UIGestureRecognizer *)recogn

- (RNGestureHandlerEventExtraData *)eventExtraData:(NSGestureRecognizer *)recognizer
{
return [RNGestureHandlerEventExtraData forPosition:[recognizer locationInView:recognizer.view]
return [RNGestureHandlerEventExtraData forPosition:[recognizer locationInView:self.coordinateView]
withAbsolutePosition:[recognizer locationInView:recognizer.view.window.contentView]
withNumberOfTouches:1
withDuration:[(RNBetterLongPressGestureRecognizer *)recognizer getDuration]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
#if TARGET_OS_OSX
- (RNGestureHandlerEventExtraData *)eventExtraData:(NSPanGestureRecognizer *)recognizer
{
return [RNGestureHandlerEventExtraData forPan:[recognizer locationInView:recognizer.view]
return [RNGestureHandlerEventExtraData forPan:[recognizer locationInView:self.coordinateView]
withAbsolutePosition:[recognizer locationInView:recognizer.view.window.contentView]
withTranslation:[recognizer translationInView:recognizer.view.window.contentView]
withVelocity:[recognizer velocityInView:recognizer.view.window.contentView]
Expand All @@ -466,7 +466,7 @@ - (RNGestureHandlerEventExtraData *)eventExtraData:(UIPanGestureRecognizer *)rec
RNBetterPanGestureRecognizer *panRecognizer = (RNBetterPanGestureRecognizer *)recognizer;

return [RNGestureHandlerEventExtraData
forPan:[recognizer locationInView:recognizer.view]
forPan:[recognizer locationInView:self.coordinateView]
withAbsolutePosition:[recognizer locationInView:recognizer.view.window]
withTranslation:[recognizer translationInView:recognizer.view.window]
withVelocity:[recognizer velocityInView:recognizer.view.window]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ - (instancetype)initWithTag:(NSNumber *)tag
- (RNGestureHandlerEventExtraData *)eventExtraData:(NSMagnificationGestureRecognizer *)recognizer
{
return [RNGestureHandlerEventExtraData forPinch:recognizer.magnification
withFocalPoint:[recognizer locationInView:recognizer.view]
withFocalPoint:[recognizer locationInView:self.coordinateView]
withVelocity:((RNBetterPinchRecognizer *)recognizer).velocity
withNumberOfTouches:2
withPointerType:RNGestureHandlerMouse];
Expand All @@ -177,20 +177,21 @@ - (RNGestureHandlerEventExtraData *)eventExtraData:(UIPinchGestureRecognizer *)r
{
CGPoint focalPoint;
NSUInteger numberOfTouches = recognizer.numberOfTouches;
RNGHUIView *coordinateView = self.coordinateView;

if (numberOfTouches > 0) {
CGPoint accumulatedPoint = CGPointZero;

for (int i = 0; i < numberOfTouches; i++) {
CGPoint location = [recognizer locationOfTouch:i inView:recognizer.view];
CGPoint location = [recognizer locationOfTouch:i inView:coordinateView];
accumulatedPoint.x += location.x;
accumulatedPoint.y += location.y;
}

focalPoint = CGPointMake(accumulatedPoint.x / numberOfTouches, accumulatedPoint.y / numberOfTouches);
} else {
// Trackpad pinch gestures may report 0 touches - use the recognizer's location instead
focalPoint = [recognizer locationInView:recognizer.view];
focalPoint = [recognizer locationInView:coordinateView];
}

return [RNGestureHandlerEventExtraData forPinch:recognizer.scale
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ - (instancetype)initWithTag:(NSNumber *)tag
- (RNGestureHandlerEventExtraData *)eventExtraData:(NSRotationGestureRecognizer *)recognizer
{
return [RNGestureHandlerEventExtraData forRotation:-recognizer.rotation
withAnchorPoint:[recognizer locationInView:recognizer.view]
withAnchorPoint:[recognizer locationInView:self.coordinateView]
withVelocity:((RNBetterRotationRecognizer *)recognizer).velocity
withNumberOfTouches:2
withPointerType:RNGestureHandlerMouse];
Expand All @@ -170,7 +170,7 @@ - (RNGestureHandlerEventExtraData *)eventExtraData:(NSRotationGestureRecognizer
- (RNGestureHandlerEventExtraData *)eventExtraData:(UIRotationGestureRecognizer *)recognizer
{
return [RNGestureHandlerEventExtraData forRotation:recognizer.rotation
withAnchorPoint:[recognizer locationInView:recognizer.view]
withAnchorPoint:[recognizer locationInView:self.coordinateView]
withVelocity:recognizer.velocity
withNumberOfTouches:recognizer.numberOfTouches
withPointerType:_pointerType];
Expand Down
11 changes: 11 additions & 0 deletions packages/react-native-gesture-handler/apple/RNGestureHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@
@property (nonatomic, copy, nullable) NSNumber *viewTag;
@property (nonatomic, readonly) RNGestureHandlerState lastState;

/**
The view whose coordinate space should be used when reporting event positions to JS.
Handlers attached via the V3 NativeDetector are bound to the `RNGestureHandlerDetector` wrapper,
which never carries user-applied transforms — those live on its child. When the detector has
exactly one subview we descend into it so reported coordinates match the visible (transformed)
view, the same coordinate space V2 and the V3 VirtualGestureDetector report in. With multiple
subviews there is no JS-side way to disambiguate which child caught the pointer, so we keep
the detector itself as the reference frame.
*/
@property (nonatomic, readonly, nullable) RNGHUIView *coordinateView;

- (BOOL)isViewParagraphComponent:(nullable RNGHUIView *)view;
- (nonnull RNGHUIView *)chooseViewForInteraction:(nonnull UIGestureRecognizer *)recognizer;
- (void)bindToView:(nonnull RNGHUIView *)view;
Expand Down
14 changes: 12 additions & 2 deletions packages/react-native-gesture-handler/apple/RNGestureHandler.mm
Original file line number Diff line number Diff line change
Expand Up @@ -286,12 +286,12 @@ - (void)unbindFromView
- (RNGestureHandlerEventExtraData *)eventExtraData:(UIGestureRecognizer *)recognizer
{
#if TARGET_OS_OSX
return [RNGestureHandlerEventExtraData forPosition:[recognizer locationInView:recognizer.view]
return [RNGestureHandlerEventExtraData forPosition:[recognizer locationInView:self.coordinateView]
withAbsolutePosition:[recognizer locationInView:recognizer.view.window.contentView]
withNumberOfTouches:1
withPointerType:RNGestureHandlerMouse];
#else
return [RNGestureHandlerEventExtraData forPosition:[recognizer locationInView:recognizer.view]
return [RNGestureHandlerEventExtraData forPosition:[recognizer locationInView:self.coordinateView]
withAbsolutePosition:[recognizer locationInView:recognizer.view.window]
withNumberOfTouches:recognizer.numberOfTouches
withPointerType:_pointerType];
Expand All @@ -307,6 +307,16 @@ - (RNGHUIView *)chooseViewForInteraction:(UIGestureRecognizer *)recognizer
return [self isViewParagraphComponent:recognizer.view] ? recognizer.view.subviews[0] : recognizer.view;
}

- (RNGHUIView *)coordinateView
{
RNGHUIView *recognizerView = _recognizer.view;
if ([self usesNativeOrVirtualDetector] && recognizerView == self.hostDetectorView &&
recognizerView.subviews.count == 1) {
return recognizerView.subviews[0];
}
return recognizerView;
Comment thread
m-bert marked this conversation as resolved.
}

- (BOOL)shouldSuppressActiveEvent:(RNGestureHandlerEventExtraData *)extraData
{
return NO;
Expand Down
Loading