fix: Prevent tab bar from being overlapped by Android navigation buttons

- Add SafeAreaProvider wrapper in root layout for reliable insets on Android
- Add minimum 16px bottom padding on Android to prevent overlap with
  gesture navigation or software buttons (Samsung, Pixel, etc.)
- Keep 10px minimum for other platforms

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Sergei 2026-01-24 20:59:49 -08:00
parent fa5d4ffb23
commit 5d2e8c029f
2 changed files with 21 additions and 14 deletions

View File

@ -1,5 +1,6 @@
import { Tabs } from 'expo-router'; import { Tabs } from 'expo-router';
import React from 'react'; import React from 'react';
import { Platform } from 'react-native';
import { Feather } from '@expo/vector-icons'; import { Feather } from '@expo/vector-icons';
import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useSafeAreaInsets } from 'react-native-safe-area-context';
@ -13,10 +14,13 @@ export default function TabLayout() {
const insets = useSafeAreaInsets(); const insets = useSafeAreaInsets();
// Calculate tab bar height based on safe area // Calculate tab bar height based on safe area
// On Android with navigation buttons (Samsung), insets.bottom is the nav bar height
// On iOS with home indicator, insets.bottom is ~34px // On iOS with home indicator, insets.bottom is ~34px
// Minimum padding of 10px for devices without safe area // On Android with gesture navigation or software buttons (Samsung/Pixel):
const bottomPadding = Math.max(insets.bottom, 10); // - insets.bottom should reflect the navigation bar height
// - But some devices/modes may return 0, so we add a minimum for Android
// Android minimum: 16px to ensure content doesn't touch system buttons
const androidMinPadding = Platform.OS === 'android' ? 16 : 0;
const bottomPadding = Math.max(insets.bottom, androidMinPadding, 10);
const tabBarHeight = 60 + bottomPadding; // 60px for content + safe area padding const tabBarHeight = 60 + bottomPadding; // 60px for content + safe area padding
return ( return (

View File

@ -8,6 +8,7 @@ import { StatusBar } from 'expo-status-bar';
import * as SplashScreen from 'expo-splash-screen'; import * as SplashScreen from 'expo-splash-screen';
import 'react-native-reanimated'; import 'react-native-reanimated';
import { KeyboardProvider } from 'react-native-keyboard-controller'; import { KeyboardProvider } from 'react-native-keyboard-controller';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { useColorScheme } from '@/hooks/use-color-scheme'; import { useColorScheme } from '@/hooks/use-color-scheme';
import { AuthProvider, useAuth } from '@/contexts/AuthContext'; import { AuthProvider, useAuth } from '@/contexts/AuthContext';
@ -63,16 +64,18 @@ function RootLayoutNav() {
export default function RootLayout() { export default function RootLayout() {
return ( return (
<KeyboardProvider> <SafeAreaProvider>
<AuthProvider> <KeyboardProvider>
<BeneficiaryProvider> <AuthProvider>
<VoiceTranscriptProvider> <BeneficiaryProvider>
<VoiceCallProvider> <VoiceTranscriptProvider>
<RootLayoutNav /> <VoiceCallProvider>
</VoiceCallProvider> <RootLayoutNav />
</VoiceTranscriptProvider> </VoiceCallProvider>
</BeneficiaryProvider> </VoiceTranscriptProvider>
</AuthProvider> </BeneficiaryProvider>
</KeyboardProvider> </AuthProvider>
</KeyboardProvider>
</SafeAreaProvider>
); );
} }