Why does the Android bottom home bar cover the React-Navigation-bottom-tabs element?
On iOS 🍏, it looks fine:
On Android 🤖, it looks like this:
I have the SafeAreaProvider
wrapping the app:
<SafeAreaProvider onLayout={onLayoutRootView}>
<ThemeProvider theme={theme}>
<ColorModeSwitch>
<StatusBar style="auto" />
<MessageProvider>
<SWRConfig value={{ shouldRetryOnError: false }}>
<AuthProvider>
<Stack
screenOptions={{
headerShown: false,
headerLeft: undefined,
}}
/>
</AuthProvider>
</SWRConfig>
</MessageProvider>
</ColorModeSwitch>
</ThemeProvider>
</SafeAreaProvider>
I tried adding SafeAreaView
to different parts of the app. Inside the ColorModeSwitch
, I thought it would be good to use a single SafeAreaView which wraps the whole app. Is this considered OK, or should it wrap each page view? The problem with this approach is that it's adding bottom padding to the iOS view bottom-navigation-tabs, which I don't want.
I tried an implementation of SafeAreaView into my custom PageView
which is a wrapper component around each Screen's View, inside the Stack &/or Tab navigation screen. This too did not change the bottom tabs:
const PageView = ({ children, style }: Props) => {
const styles = useStyles();
return (
<SafeAreaView style={[styles.container, style]}>{children}</SafeAreaView>
);
};
I am using Expo & Expo-Router for my navigation & Tabs:
export default function TabLayout() {
return (
<>
<Tabs
initialRouteName="home"
screenOptions={{
headerShown: false,
}}
tabBar={props => (
<Shadow distance={60} offset={[0, 20]} stretch>
<TabBar {...props} />
</Shadow>
)}
>
<Tabs.Screen
name="index"
options={{
tabBarLabel: 'Home',
}}
/>
<Tabs.Screen
listeners={({ navigation }: BottomTabScreenProps<any>) => ({
tabPress: (e: EventArg<'tabPress', true>) => {
e.preventDefault();
navigation.navigate('scanModal');
return;
},
})}
name="scan"
options={{
tabBarLabel: 'Scan',
}}
/>
<Tabs.Screen
name="profile"
options={{
tabBarLabel: 'Profile',
}}
/>
</Tabs>
</>
);
}
So I tried adding SafeAreaView as the Wrapper to my custom bottom nav tab elements:
const insets = useSafeAreaInsets();
return (
<SafeAreaView
style={{
paddingBottom: insets.bottom,
flexDirection: 'row',
height: 80,
backgroundColor: theme.colors.white,
alignItems: 'center',
}}
>
But this made it worse:
What is an option to fix this on Android?
Use useSafeAreaInsets
to get the bottom inset and set the value as paddingBottom
in a custom tab bar. Something like this:
import { useSafeAreaInsets } from 'react-native-safe-area-context';
function CustomTabBar({ state, descriptors, navigation }) {
const insets = useSafeAreaInsets();
return (
<View style={{ paddingBottom: insets.bottom }}>
...
</View>
);
}
<Tab.Navigator
tabBar={(props) => <CustomTabBar {...props} />}>
...
</Tab.Navigator>