From 4e4d3fda7c61eb46593dee8d7b85d64686e8e7fc Mon Sep 17 00:00:00 2001 From: Oleksii Bulenok Date: Tue, 14 Jul 2026 15:23:32 +0200 Subject: [PATCH] Fix full-screen back gesture over PagerView on iOS 26 again --- patches/react-native-pager-view@6.8.0.patch | 47 ++++++++++++++++++- .../react-native-pager-view@6.8.0.patch.md | 2 + 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/patches/react-native-pager-view@6.8.0.patch b/patches/react-native-pager-view@6.8.0.patch index 0abf294bbe..cc3968ac89 100644 --- a/patches/react-native-pager-view@6.8.0.patch +++ b/patches/react-native-pager-view@6.8.0.patch @@ -1,5 +1,5 @@ diff --git a/ios/Fabric/RNCPagerViewComponentView.mm b/ios/Fabric/RNCPagerViewComponentView.mm -index 652a5c123100e7010011f07649517aa9e0cbc554..9e038c353298f33f4f0fdb9d01cec38841b7a5c9 100644 +index 652a5c123100e7010011f07649517aa9e0cbc554..efbc3af622c4fee8267a78144b906c7b5de7859c 100644 --- a/ios/Fabric/RNCPagerViewComponentView.mm +++ b/ios/Fabric/RNCPagerViewComponentView.mm @@ -90,6 +90,62 @@ - (void)willMoveToSuperview:(UIView *)newSuperview { @@ -79,6 +79,51 @@ index 652a5c123100e7010011f07649517aa9e0cbc554..9e038c353298f33f4f0fdb9d01cec388 _nativePageViewController = nil; _currentIndex = -1; } +@@ -421,8 +484,44 @@ + (ComponentDescriptorProvider)componentDescriptorProvider + } + + ++/* ++ * Finds the navigation controller managing this pager via the responder ++ * chain, so the pager can cooperate with the controller's back gesture. ++ */ ++- (UINavigationController *)nearestNavigationController { ++ UIResponder *responder = self.nextResponder; ++ while (responder != nil) { ++ if ([responder isKindOfClass:[UINavigationController class]]) { ++ return (UINavigationController *)responder; ++ } ++ responder = responder.nextResponder; ++ } ++ return nil; ++} ++ + - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { + ++ // iOS 26+ full-screen back gesture (interactiveContentPopGestureRecognizer) ++ if (@available(iOS 26.0, *)) { ++ if (gestureRecognizer == self.panGestureRecognizer && ++ otherGestureRecognizer != nil && ++ otherGestureRecognizer == [self nearestNavigationController].interactiveContentPopGestureRecognizer) { ++ UIPanGestureRecognizer* panGestureRecognizer = (UIPanGestureRecognizer*) gestureRecognizer; ++ CGPoint velocity = [panGestureRecognizer velocityInView:self]; ++ BOOL isLTR = [self isLtrLayout]; ++ BOOL isBackGesture = (isLTR && velocity.x > 0) || (!isLTR && velocity.x < 0); ++ ++ if (self.currentIndex == 0 && isBackGesture) { ++ scrollView.panGestureRecognizer.enabled = false; ++ } else { ++ const auto &viewProps = *std::static_pointer_cast(_props); ++ scrollView.panGestureRecognizer.enabled = viewProps.scrollEnabled; ++ } ++ ++ return YES; ++ } ++ } ++ + // Recognize simultaneously only if the other gesture is RN Screen's pan gesture (one that is used to perform fullScreenGestureEnabled) + if (gestureRecognizer == self.panGestureRecognizer && [NSStringFromClass([otherGestureRecognizer class]) isEqual: @"RNSPanGestureRecognizer"]) { + UIPanGestureRecognizer* panGestureRecognizer = (UIPanGestureRecognizer*) gestureRecognizer; diff --git a/ios/RNCPagerView.m b/ios/RNCPagerView.m index adfc7c6f2224b898a02319d352bb4fe11a18fd7e..939bb801c5b0ca6f93b77cb0507c19d137e08e77 100644 --- a/ios/RNCPagerView.m diff --git a/patches/react-native-pager-view@6.8.0.patch.md b/patches/react-native-pager-view@6.8.0.patch.md index ea967c87b8..9e99dc4a1c 100644 --- a/patches/react-native-pager-view@6.8.0.patch.md +++ b/patches/react-native-pager-view@6.8.0.patch.md @@ -6,6 +6,8 @@ The pager already handles `RNSPanGestureRecognizer` (react-native-screens' custo This patch adds the same logic for iOS 26's native `interactiveContentPopGestureRecognizer`, so the back gesture works on the leftmost page while the pager still handles swipes on other pages. +The fix is applied to both implementations: `ios/RNCPagerView.m` (Paper) and `ios/Fabric/RNCPagerViewComponentView.mm` (New Architecture). The Fabric variant finds the navigation controller via the responder chain (there is no `reactViewController` helper imported there) and reads `scrollEnabled` from the Fabric props. + Related issues: - https://github.com/software-mansion/react-native-screens/issues/3512 - https://github.com/software-mansion/react-native-screens/pull/3420