Repository navigation
Conversation
A SafeAreaProvider that is laid out but outside a window (for example a tab of a native tab container that was never selected) reports zero safeAreaInsets. A keyboard notification then sent that zero to JS, so the tab's first frame painted with top: 0 and jumped when the real inset arrived. Skip the measurement without a window, as RNCSafeAreaViewComponentView already does, and request a layout pass when the view enters a window so the first report is always sent. Fixes #806 Co-authored-by: Nick Lamont <39568874+nicklamont@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
Author
This branch has not been deployed
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 #806. cc @janicduplessis
On iOS (Fabric),
RNCSafeAreaProviderComponentViewlistens for keyboard notifications on every instance and each one callsinvalidateSafeAreaInsets.... That method checkedsuperviewand a zero frame but notwindow. A view outside a window reportssafeAreaInsetsof zero, so one keyboard event made every provider that was laid out but not in a window sendtop: 0to JS. With native tab containers, the first open of each never-selected tab then painted under the status bar and jumped when the real inset arrived.The change:
invalidateSafeAreaInsetsMeasuringCorners:whenself.window == nil(iOS/tvOS/visionOS; macOS untouched).RNCSafeAreaViewComponentViewalready has this guard.didMoveToWindow, which callssetNeedsLayout, so a provider whose in-window insets equal the zero it held outside still sends its first report (safeAreaInsetsDidChangeonly fires on change). It asks for layout instead of measuring directly because UIKit may not have updatedsafeAreaInsetsat that point.The diagnosis and patch are from @nicklamont's report in #806, who also offered to open the PR. I only validated and wrapped it.
Not changed: the legacy (Paper)
ios/RNCSafeAreaProvider.mhas the same unguarded path. The report is Fabric-only, so I left it out of this PR.Test Plan
No test added: the repo has no iOS unit test target, and the behaviour depends on UIKit window/keyboard events.
Validated on an iOS 27.0 simulator (iPhone 17 Pro) in the example app (Fabric, RN 0.85), temporarily replacing the example's
Appwith a repro that is not part of this PR:@react-navigation/bottom-tabs/unstablenative tabs withlazy: false, each tab wrapped in its ownSafeAreaListener(same native provider view) that records thetopof everyonInsetsChange, and aTextInputon tab A.Steps: cold start on tab A, focus the
TextInput(software keyboard shows), dismiss it, then select tab B and tab C for the first time.main)[0, 116][0, 116][116][116]Before, each tab's provider sent
top: 0at the keyboard event and then 116 when it entered the window. After, the provider sends nothing outside the window and one correct report on entry. Screenshots of tab B before and after are attached in the next comment.Also run:
yarn validate:typescriptandyarn validate:jestpass.clang-formathas no linux-arm64 binary on my machine, so the diff was formatted by hand to the repo's 120 column style; CI will check it. This repro uses react-navigation's native tabs rather than expo-router'sNativeTabsfrom the report.