Repository navigation
Conversation
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. The workaround lives in its own file and every entry point returns early on iOS 16+, so deleting the file and its single call site in PagerViewProvider.swift is all that is needed once iOS 15 support is dropped.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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