fix(Android, Stack v4): fall back to rootWindowInsets for status bar top when ancestor consumed insets#3870
Conversation
…top when ancestor consumed insets When an ancestor view (e.g. SafeAreaProvider from react-native-safe-area-context) consumes the systemBars top inset, unhandledInsets.top becomes 0. As a result, CustomToolbar computes paddingTop = 0 and the header title renders behind the status bar on Android 15 (SDK 35) with edge-to-edge enabled. Fix: for the status bar top height specifically, fall back to rootWindowInsets when unhandledInsets.top == 0. rootWindowInsets always contains the raw window insets regardless of what ancestor views have consumed. This preserves the intent of software-mansion#3240 (use ancestor-received insets when available) while fixing the regression on setups with SafeAreaProvider wrapping the app.
kkafar
left a comment
There was a problem hiding this comment.
Thanks for the contribution.
@t0maboro could I get your attention here, please? You have the most context now regarding inset handling on Android. How does the problem OP indicates relate to changes we have already made / have planned?
|
It was a problem with а package react-native-keyborad-controller. Last fix helped me I think you could close this PR, thx 🙏 |
|
Hi @khorark , thanks for the contribution! In this PR: #3793, I added support for applying padding to the header by reading insets from the For now, I'm going to close this PR. |
Description
Fixes a regression introduced in #3240 where the native stack header title renders behind the status bar on Android 15 (SDK 35) with edge-to-edge enabled.
Root cause
PR #3240 changed
CustomToolbar.onApplyWindowInsetsto readsystemBarsinsets fromunhandledInsets(received from ancestor views) instead ofrootWindowInsets.When
SafeAreaProviderfromreact-native-safe-area-contextwraps the app (standard setup), it consumes thesystemBars.topinset before it reachesCustomToolbar. As a result:So
CustomToolbarcomputespaddingTop = 0and the toolbar title renders at y=0, visually behind the status bar.Before #3240,
rootWindowInsetswas used withignoreVisibility = true, which always provided a stable, non-zero status bar height regardless of what ancestors consumed.Fix
For the status bar top height specifically, fall back to
rootWindowInsetswhenunhandledInsets.top == 0.rootWindowInsetsalways contains the raw window insets that no ancestor can consume:This preserves the intent of #3240 (use ancestor-received insets when available) while fixing the regression when an ancestor has already consumed the top inset.
Affected versions
rootWindowInsets, worked correctly)Changes
CustomToolbar.kt: fall back torootWindowInsetsforstatusBarTopwhenunhandledInsets.top == 0Test code and steps to reproduce
edgeToEdgeEnabled=trueingradle.properties)SafeAreaProviderfromreact-native-safe-area-context(standard setup)createNativeStackNavigatorExpected: Header title appears below the status bar
Actual (4.19.0+): Header title renders behind/under the status bar
Environment
edgeToEdgeEnabled=true@react-navigation/native-stack: 7.6.1react-native-safe-area-context: ^5.7.0Checklist