Skip to content

Commit 294e670

Browse files
committed
fix(mobile): disable KeyboardProvider on Android to fix header inset
KeyboardProvider's EdgeToEdgeReactViewGroup intercepts window insets at the root view level and zeros out the status bar top inset on Android. This prevents react-native-screens' CustomToolbar from receiving the correct system bar insets, causing headers to appear cramped against the status bar. Skip KeyboardProvider on Android entirely via a RootKeyboardProvider wrapper. Also remove unnecessary transparent headerStyle background on Android tab layouts. Refs: - kirillzyusko/react-native-keyboard-controller#1013 - kirillzyusko/react-native-keyboard-controller#1292
1 parent 119efef commit 294e670

7 files changed

Lines changed: 20 additions & 25 deletions

File tree

apps/mobile/app/_layout.tsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import "@/globals.css";
22
import "expo-dev-client";
33

4+
import type React from "react";
45
import { useEffect } from "react";
56
import { Platform } from "react-native";
67
import { GestureHandlerRootView } from "react-native-gesture-handler";
@@ -18,6 +19,22 @@ import { cn } from "@/lib/utils";
1819
import { NAV_THEME } from "@/theme";
1920
import { ThemeProvider as NavThemeProvider } from "@react-navigation/native";
2021

22+
// On Android, KeyboardProvider's EdgeToEdgeReactViewGroup intercepts window insets at
23+
// the root view level, zeroing out the status bar top inset. This prevents the native
24+
// navigation toolbar (react-native-screens' CustomToolbar) from receiving the correct
25+
// system bar insets, resulting in headers appearing cramped against the status bar.
26+
// We skip KeyboardProvider on Android entirely to let the toolbar handle its own insets.
27+
function RootKeyboardProvider({ children }: { children: React.ReactNode }) {
28+
if (Platform.OS === "android") {
29+
return children;
30+
}
31+
return (
32+
<KeyboardProvider statusBarTranslucent navigationBarTranslucent>
33+
{children}
34+
</KeyboardProvider>
35+
);
36+
}
37+
2138
export default function RootLayout() {
2239
useInitialAndroidBarSync();
2340
const router = useRouter();
@@ -34,10 +51,7 @@ export default function RootLayout() {
3451

3552
return (
3653
<SafeAreaProvider>
37-
<KeyboardProvider
38-
statusBarTranslucent={Platform.OS !== "android" ? true : undefined}
39-
navigationBarTranslucent={Platform.OS !== "android" ? true : undefined}
40-
>
54+
<RootKeyboardProvider>
4155
<NavThemeProvider value={NAV_THEME[colorScheme]}>
4256
<SplashScreenController />
4357
<StyledStack
@@ -128,7 +142,7 @@ export default function RootLayout() {
128142
/>
129143
</StyledStack>
130144
</NavThemeProvider>
131-
</KeyboardProvider>
145+
</RootKeyboardProvider>
132146
<StatusBar
133147
key={`root-status-bar-${isDarkColorScheme ? "light" : "dark"}`}
134148
style={isDarkColorScheme ? "light" : "dark"}

apps/mobile/app/dashboard/(tabs)/(highlights)/_layout.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ export default function Layout() {
1414
headerLargeStyle: { backgroundColor: "transparent" },
1515
},
1616
android: {
17-
headerStyle: {
18-
backgroundColor: "transparent",
19-
},
2017
contentStyle: {
2118
// Manual padding to avoid the native tabbar until expo fixes this in sdk 55.
2219
paddingBottom: 100,

apps/mobile/app/dashboard/(tabs)/(home)/_layout.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ export default function Layout() {
1414
headerLargeStyle: { backgroundColor: "transparent" },
1515
},
1616
android: {
17-
headerStyle: {
18-
backgroundColor: "transparent",
19-
},
2017
contentStyle: {
2118
// Manual padding to avoid the native tabbar until expo fixes this in sdk 55.
2219
paddingBottom: 100,

apps/mobile/app/dashboard/(tabs)/(lists)/_layout.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ export default function Layout() {
1414
headerLargeStyle: { backgroundColor: "transparent" },
1515
},
1616
android: {
17-
headerStyle: {
18-
backgroundColor: "transparent",
19-
},
2017
contentStyle: {
2118
// Manual padding to avoid the native tabbar until expo fixes this in sdk 55.
2219
paddingBottom: 100,

apps/mobile/app/dashboard/(tabs)/(settings)/_layout.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ export default function Layout() {
1414
headerLargeStyle: { backgroundColor: "transparent" },
1515
},
1616
android: {
17-
headerStyle: {
18-
backgroundColor: "transparent",
19-
},
2017
contentStyle: {
2118
// Manual padding to avoid the native tabbar until expo fixes this in sdk 55.
2219
paddingBottom: 100,

apps/mobile/app/dashboard/(tabs)/(tags)/_layout.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ export default function Layout() {
1414
headerLargeStyle: { backgroundColor: "transparent" },
1515
},
1616
android: {
17-
headerStyle: {
18-
backgroundColor: "transparent",
19-
},
2017
contentStyle: {
2118
// Manual padding to avoid the native tabbar until expo fixes this in sdk 55.
2219
paddingBottom: 100,

apps/mobile/app/dashboard/_layout.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,7 @@ export default function Dashboard() {
3939
headerLargeTitleShadowVisible: false,
4040
headerLargeStyle: { backgroundColor: "transparent" },
4141
},
42-
android: {
43-
headerStyle: {
44-
backgroundColor: "transparent",
45-
},
46-
},
42+
android: {},
4743
}),
4844
headerShadowVisible: false,
4945
}}

0 commit comments

Comments
 (0)