diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm index 67d8e893cf..915059c403 100644 --- a/ios/RNSScreenStack.mm +++ b/ios/RNSScreenStack.mm @@ -600,20 +600,14 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { RNSScreenView *topScreen = (RNSScreenView *)_controller.viewControllers.lastObject.view; - if (![topScreen isKindOfClass:[RNSScreenView class]] || !topScreen.gestureEnabled || - _controller.viewControllers.count < 2) { - return NO; - } - #if TARGET_OS_TV [self cancelTouchesInParent]; return YES; #else - if (topScreen.fullScreenSwipeEnabled) { - // we want only `RNSPanGestureRecognizer` to be able to recognize when - // `fullScreenSwipeEnabled` is set, and we are in the bounds set by user - if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]] && - [self isInGestureResponseDistance:gestureRecognizer topScreen:topScreen]) { + // RNSPanGestureRecognizer will receive events iff topScreen.fullScreenSwipeEnabled == YES; + // Events are filtered in gestureRecognizer:shouldReceiveEvent: method + if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) { + if ([self isInGestureResponseDistance:gestureRecognizer topScreen:topScreen]) { _isFullWidthSwiping = YES; [self cancelTouchesInParent]; return YES; @@ -621,6 +615,7 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer return NO; } + // Now we're dealing with RNSScreenEdgeGestureRecognizer (or _UIParallaxTransitionPanGestureRecognizer) if (topScreen.customAnimationOnSwipe && [RNSScreenStackAnimator isCustomAnimation:topScreen.stackAnimation]) { if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) { // if we do not set any explicit `semanticContentAttribute`, it is `UISemanticContentAttributeUnspecified` instead @@ -639,10 +634,8 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) { // it should only recognize with `customAnimationOnSwipe` set return NO; - } else if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) { - // it should only recognize with `fullScreenSwipeEnabled` set - return NO; } + // _UIParallaxTransitionPanGestureRecognizer (other...) [self cancelTouchesInParent]; return YES; } @@ -819,16 +812,51 @@ - (BOOL)isScrollViewPanGestureRecognizer:(UIGestureRecognizer *)gestureRecognize return scrollView.panGestureRecognizer == gestureRecognizer; } +// RNSScreenStackView is a UIGestureRecognizerDelegate for three types of gesture recognizers: +// RNSPanGestureRecognizer, RNSScreenEdgeGestureRecognizer, _UIParallaxTransitionPanGestureRecognizer +// Be careful when adding another type of gesture recognizer. +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveEvent:(UIEvent *)event +{ + RNSScreenView *topScreen = (RNSScreenView *)_controller.viewControllers.lastObject.view; + + if (![topScreen isKindOfClass:[RNSScreenView class]] || !topScreen.gestureEnabled || + _controller.viewControllers.count < 2) { + return NO; + } + + // We want to pass events to RNSPanGestureRecognizer iff full screen swipe is enabled. + if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) { + return topScreen.fullScreenSwipeEnabled; + } + + // RNSScreenEdgeGestureRecognizer || _UIParallaxTransitionPanGestureRecognizer + return YES; +} + - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { - return [self isScrollViewPanGestureRecognizer:otherGestureRecognizer]; + if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]] && + [self isScrollViewPanGestureRecognizer:otherGestureRecognizer]) { + RNSPanGestureRecognizer *panGestureRecognizer = (RNSPanGestureRecognizer *)gestureRecognizer; + BOOL isBackGesture = [panGestureRecognizer translationInView:panGestureRecognizer.view].x > 0 && + _controller.viewControllers.count > 1; + + if (gestureRecognizer.state == UIGestureRecognizerStateBegan || isBackGesture) { + return NO; + } + + return YES; + } + return NO; } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { - return [self isScrollViewPanGestureRecognizer:otherGestureRecognizer]; + return ( + [gestureRecognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]] && + [self isScrollViewPanGestureRecognizer:otherGestureRecognizer]); } - (void)insertReactSubview:(RNSScreenView *)subview atIndex:(NSInteger)atIndex