Skip to content

Commit 23fb6da

Browse files
authored
fix: handle multiple gesture recognizers (#1512)
* fix: handle multiple gesture recognizers * fix: improve gestureRecognizer logic * chore: make screen stack gesture recognizers do not receive events in some cases Now screen stack gesture recognizers do not receive events when gestures are disabled or there is no screen to navigate to * chore: simplify & improve gesture recognizer logic
1 parent b78d2e9 commit 23fb6da

1 file changed

Lines changed: 43 additions & 15 deletions

File tree

ios/RNSScreenStack.mm

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -600,27 +600,22 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
600600
{
601601
RNSScreenView *topScreen = (RNSScreenView *)_controller.viewControllers.lastObject.view;
602602

603-
if (![topScreen isKindOfClass:[RNSScreenView class]] || !topScreen.gestureEnabled ||
604-
_controller.viewControllers.count < 2) {
605-
return NO;
606-
}
607-
608603
#if TARGET_OS_TV
609604
[self cancelTouchesInParent];
610605
return YES;
611606
#else
612-
if (topScreen.fullScreenSwipeEnabled) {
613-
// we want only `RNSPanGestureRecognizer` to be able to recognize when
614-
// `fullScreenSwipeEnabled` is set, and we are in the bounds set by user
615-
if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]] &&
616-
[self isInGestureResponseDistance:gestureRecognizer topScreen:topScreen]) {
607+
// RNSPanGestureRecognizer will receive events iff topScreen.fullScreenSwipeEnabled == YES;
608+
// Events are filtered in gestureRecognizer:shouldReceiveEvent: method
609+
if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) {
610+
if ([self isInGestureResponseDistance:gestureRecognizer topScreen:topScreen]) {
617611
_isFullWidthSwiping = YES;
618612
[self cancelTouchesInParent];
619613
return YES;
620614
}
621615
return NO;
622616
}
623617

618+
// Now we're dealing with RNSScreenEdgeGestureRecognizer (or _UIParallaxTransitionPanGestureRecognizer)
624619
if (topScreen.customAnimationOnSwipe && [RNSScreenStackAnimator isCustomAnimation:topScreen.stackAnimation]) {
625620
if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) {
626621
// if we do not set any explicit `semanticContentAttribute`, it is `UISemanticContentAttributeUnspecified` instead
@@ -639,10 +634,8 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
639634
if ([gestureRecognizer isKindOfClass:[RNSScreenEdgeGestureRecognizer class]]) {
640635
// it should only recognize with `customAnimationOnSwipe` set
641636
return NO;
642-
} else if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) {
643-
// it should only recognize with `fullScreenSwipeEnabled` set
644-
return NO;
645637
}
638+
// _UIParallaxTransitionPanGestureRecognizer (other...)
646639
[self cancelTouchesInParent];
647640
return YES;
648641
}
@@ -819,16 +812,51 @@ - (BOOL)isScrollViewPanGestureRecognizer:(UIGestureRecognizer *)gestureRecognize
819812
return scrollView.panGestureRecognizer == gestureRecognizer;
820813
}
821814

815+
// RNSScreenStackView is a UIGestureRecognizerDelegate for three types of gesture recognizers:
816+
// RNSPanGestureRecognizer, RNSScreenEdgeGestureRecognizer, _UIParallaxTransitionPanGestureRecognizer
817+
// Be careful when adding another type of gesture recognizer.
818+
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveEvent:(UIEvent *)event
819+
{
820+
RNSScreenView *topScreen = (RNSScreenView *)_controller.viewControllers.lastObject.view;
821+
822+
if (![topScreen isKindOfClass:[RNSScreenView class]] || !topScreen.gestureEnabled ||
823+
_controller.viewControllers.count < 2) {
824+
return NO;
825+
}
826+
827+
// We want to pass events to RNSPanGestureRecognizer iff full screen swipe is enabled.
828+
if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]]) {
829+
return topScreen.fullScreenSwipeEnabled;
830+
}
831+
832+
// RNSScreenEdgeGestureRecognizer || _UIParallaxTransitionPanGestureRecognizer
833+
return YES;
834+
}
835+
822836
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
823837
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
824838
{
825-
return [self isScrollViewPanGestureRecognizer:otherGestureRecognizer];
839+
if ([gestureRecognizer isKindOfClass:[RNSPanGestureRecognizer class]] &&
840+
[self isScrollViewPanGestureRecognizer:otherGestureRecognizer]) {
841+
RNSPanGestureRecognizer *panGestureRecognizer = (RNSPanGestureRecognizer *)gestureRecognizer;
842+
BOOL isBackGesture = [panGestureRecognizer translationInView:panGestureRecognizer.view].x > 0 &&
843+
_controller.viewControllers.count > 1;
844+
845+
if (gestureRecognizer.state == UIGestureRecognizerStateBegan || isBackGesture) {
846+
return NO;
847+
}
848+
849+
return YES;
850+
}
851+
return NO;
826852
}
827853

828854
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
829855
shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
830856
{
831-
return [self isScrollViewPanGestureRecognizer:otherGestureRecognizer];
857+
return (
858+
[gestureRecognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]] &&
859+
[self isScrollViewPanGestureRecognizer:otherGestureRecognizer]);
832860
}
833861

834862
- (void)insertReactSubview:(RNSScreenView *)subview atIndex:(NSInteger)atIndex

0 commit comments

Comments
 (0)