Repository navigation
Conversation
ArekChr
left a comment
There was a problem hiding this comment.
@zewillze Thanks for the fix! There is one issue to fix before merging.
SwiftPM support (#1187) is now merged into main. Please update this branch and add PagerViewIOS15NavigationBarCompat.swift to the source files in ios/Package.swift. Without it, the SwiftPM build will fail.
Please also check that a native navigation bar that should be visible stays visible after opening a screen and going back on iOS 15. The current CI tests run on iOS 26.4, so they do not test this fix.
On iOS 15 SwiftUI's UIHostingController installs UIKitNavigationBarBridge, which calls -[UINavigationController setNavigationBarHidden:NO] on the enclosing navigation controller whenever the hosting view appears. When that bar is deliberately hidden - e.g. the container react-native-screens creates for hasTwoStates tab/drawer navigators - the bridge re-shows an empty UINavigationBar, which then swallows touches meant for the JS header buttons underneath. Wrap the hosting controller so it restores the previous hidden state around viewWillAppear. A bar that is already visible is left untouched, so native navigation bars keep working. The workaround lives in its own file and every entry point returns early on iOS 16+, so deleting the file (and its entry in Package.swift) together with its single call site in PagerViewProvider.swift is all that is needed once iOS 15 support is dropped.
6fac40a to
7726a61
Compare
|
hi @ArekChr The branch is rebased onto sources: [
"Extensions.swift",
"PagerScrollDelegate.swift",
"PagerView.swift",
"PagerViewIOS15Compat.swift",
"PagerViewIOS15NavigationBarCompat.swift",
"PagerViewProps.swift",
"PagerViewProvider.swift",
],I checked the list against every runtime Swift file in 2. Visible native navigation bar (iOS 15.2) Agreed that CI (iOS 26.4) does not cover this. The fix only re-hides a bar that was hidden before
The pager's hosting controller is The branch is updated: 3 files, |
Summary
Fixes the iOS 15 case where the React Navigation header buttons stop responding after a screen is pushed and popped.
Root cause. On iOS 15
UIHostingControllerinstalls SwiftUI'sUIKitNavigationBarBridge. Whenever the hosting view appears, the bridge calls-[UINavigationController setNavigationBarHidden:NO]on the enclosing navigation controller. When that bar is deliberately hidden — e.g. theRNSContainerNavigationControllerthatreact-native-screenscreates forhasTwoStatestab/drawer containers — the bridge re-shows an emptyUINavigationBaron top of the screen. It lands exactly over the JS header (frame(0 47; 428 44)in the repro) and swallows every touch there, so the header buttons never fire. It keeps that state after the pop, so the buttons stay dead.Measured with lldb on an iOS 15.2 simulator after push → pop:
UINavigationBarin the windowhitTeston the header button(0 47; 428 44),hidden = NO_UINavigationBarContentView(not the button)ButtonviewHow it was implemented. The workaround lives in its own file,
ios/PagerViewIOS15NavigationBarCompat.swift. Its single entry point starts withif #available(iOS 16, *)and returns a plainUIHostingControllerthere; on iOS 15 and below it returns aUIHostingControllersubclass that restores the enclosing navigation bar's hidden state aroundviewWillAppear.PagerViewProvider.swiftonly changes how the hosting controller is constructed (one call site).Removal. Once the minimum supported iOS version is 16, delete
ios/PagerViewIOS15NavigationBarCompat.swiftand replace that single call site withUIHostingController(...). Nothing else references it, and on iOS 16+ the file already returns a plain hosting controller.UIHostingControllerconstruction inPagerViewProvidergoes through the new factory.scrollEnabledfix (fix(ios): respect scrollEnabled on iOS 15 #1148).Test Plan
What's required for testing (prerequisites)?
Homeis a@react-navigation/stackscreen withheaderLeft/headerRight,Homecontains acreateMaterialTopTabNavigator, and the root navigator iscreateBottomTabNavigator.What are the steps to reproduce?
Detailinside the stack).UINavigationBar.Alertshows.Optional check without touches, after step 3 — dump the window hierarchy (
po [[[UIApplication sharedApplication] keyWindow] performSelector:@selector(recursiveDescription)]):UINavigationBarat(0 47; 428 44)withhidden = NO.On the fixed build the pager's hosting controller class is the compat subclass
(
PreservingNavigationBarHostingController<PagerView>), which also confirms the#availablegate took the iOS 15 path.Compatibility
Android does not have this code path and is unaffected.
Checklist
README.mdFixes #1180