Android & Expo Go was working fine for me until Expo SDK 53 using @react-navigation/native
.
As of SDK 53, Navigation is now working edge-to-edge, and that was not the way before, and I need to re-configure for this mode.
I checked forums and saw problems with SDK 53, but not mine. I also tried SafeViewProvider
without success.
I hacked some code (thanks to ... forgot your name!) to show the result below. The problem is that my views now appear underneath the status bars due to the new edge-to-edge setting (they were fine in earlier versions). Edge-to-edge can no longer be turned off in Expo Go or newer versions of Android.
I started a new project with latest versions and everything else works fine.
import { Text, View, SafeAreaView } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { registerRootComponent } from 'expo';
// Ajoute cette ligne pour forcer React Navigation à utiliser un header en pur JS
const Stack = createNativeStackNavigator({
});
const EntreeScreen = ({navigation,route}) => {
return (
<SafeAreaView style={{flex:0.92,flexDirection:"row",backgroundColor:"blue",}}>
<View style={{flex:1,backgroundColor:"white"}} />
<View
style={{
flex: 5,flexDirection:"column",
justifyContent: "center",
alignItems: "center",
backgroundColor:"lightblue",
marginTop:0,
justifyContent:"center",borderRadius:32,borderWidth:1,borderColor:"red",
}}
>
<Text style={{fontWeight: "bold",}}>CENTER TEXTE !</Text>
</View>
<View style={{flex:1,backgroundColor:"white"}} />
</SafeAreaView>
);
}
const App = () => (
<NavigationContainer >
<Stack.Navigator
screenOptions={{
title:"",
headerStyle: {
backgroundColor: 'lightgreen',
},
headerTintColor: '#888',
headerTitleStyle: {
fontWeight: 'normal',
textAlign:'center',
},
}}
>
<Stack.Screen // 01 entrée
name={"E"}
component={EntreeScreen}
options={({ navigation, route }) => ({
headerLeft: () => ( // bouton aide
<View style={{marginTop:24,alignItems:"center"}}>
<Text>LEFT</Text>
</View>
),
headerTitle: () => (
<View style={{marginTop:24}}>
<Text style={{textAlign:"center"}}>MON TITRE!</Text>
</View>
),
headerRight: () => (
<View style={{marginTop:24}}>
<Text>RIGHT</Text>
</View>
),
})}
/>
</Stack.Navigator>
</NavigationContainer>
);
registerRootComponent(App);
I got these results on my fone. One using flex:1 and the other using (as above) flex:0.92 (empirically found) !
note that if you edit the file (anything as a space in a comment) and save the title is ok!
flex:1 after minor change in the text and save ( NO REBUILD)
on my tablet the result for flex:0.92 is almost the same as with flex:1 on the fone. With 0.88 it's quite good. Just the status bar is green and the navigation lower bar does not show the 3 buttons, just a grey banner.
I'll appreciate a lot your help.
===============================
Solution can be found with API react-native-safe-area-context Here the complete functional demo program:
// App.js
import React from 'react';
import { Text, View } from 'react-native';
import {SafeAreaProvider,useSafeAreaInsets,} from 'react-native-safe-area-context';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { registerRootComponent } from 'expo';
const Stack = createNativeStackNavigator();
// --------------------
// ÉCRAN D’ENTRÉE
// --------------------
const EntreeScreen = ({ navigation, route }) => {
const insets = useSafeAreaInsets();
return (
<View
style={{
flex: 1,
flexDirection: 'row',
backgroundColor: 'blue',
// Marges dynamiques selon les safe areas
paddingBottom: insets.bottom,
paddingLeft: insets.left,
paddingRight: insets.right,
}}
>
{/* Colonne de gauche */}
<View style={{ flex: 1, backgroundColor: 'white' }} />
{/* Colonne centrale */}
<View
style={{
flex: 5,
flexDirection: 'column',
justifyContent: 'center',
backgroundColor: 'lightblue',
marginTop: 0,
borderRadius: 32,
borderWidth: 1,
borderColor: 'red',
}}
>
<Text
style={{
textAlign: 'center',
fontSize: 32,
fontWeight: 'bold',
}}
>
CENTER TEXTE !
</Text>
</View>
{/* Colonne de droite */}
<View style={{ flex: 1, backgroundColor: 'white' }} />
</View>
);
};
// --------------------
// APP PRINCIPALE
// --------------------
const App = () => (
<SafeAreaProvider>
<NavigationContainer>
<Stack.Navigator
screenOptions={{
title: '',
headerStyle: {
backgroundColor: 'lightgreen',
},
headerTintColor: 'red',
}}
>
<Stack.Screen
name="E"
component={EntreeScreen}
options={({ navigation, route }) => ({
headerLeft: () => <Text style={{ marginLeft: 8 }}>LEFT</Text>,
headerTitle: () => (
<Text
style={{
fontWeight: 'bold',
textAlign: 'center',
fontStyle: 'italic',
}}
>
MON TITRE!
</Text>
),
headerRight: () => <Text style={{ marginRight: 8 }}>RIGHT</Text>,
})}
/>
</Stack.Navigator>
</NavigationContainer>
</SafeAreaProvider>
);
registerRootComponent(App);
According to the react-navigation
docs on safe areas, you should use the react-native-safe-area-context
library to support Android instead of React Native's default SafeAreaView
:
While React Native exports a
SafeAreaView
component, this component only supports iOS 10+ with no support for older iOS versions or Android. In addition, it also has some issues, i.e. if a screen containing safe area is animating, it causes jumpy behavior. So we recommend to use theuseSafeAreaInsets
hook from the react-native-safe-area-context library to handle safe areas in a more reliable way.
We can adapt your code to use the SafeAreaProvider
in the App
component and then the useSafeAreaInsets
hook in the EntreeScreen
component as well as any additional components, such as a Header
component with custom styles:
import { registerRootComponent } from 'expo';
import { View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import {
SafeAreaProvider,
useSafeAreaInsets,
} from 'react-native-safe-area-context'; // <-- add these imports
// Ajoute cette ligne pour forcer React Navigation à utiliser un header en pur JS
const Stack = createNativeStackNavigator();
const EntreeScreen = () => {
const insets = useSafeAreaInsets(); // <-- add this hook
return (
<View
style={{
flex: 1,
paddingBottom: insets.bottom, // -- add padding to all but the top, which the header already has
paddingLeft: insets.left,
paddingRight: insets.right,
}}
>
<View
style={{
flex: 5,
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
backgroundColor: "lightblue",
marginTop: 0,
borderRadius: 32,
borderWidth: 1,
borderColor:"red",
}}
>
<Text style={{ fontWeight: "bold" }}>CENTER TEXTE !</Text>
</View>
</View>
);
}
const Header = ({text, style}) => {
const insets = useSafeAreaInsets(); // <-- add this hook
return <View
style={{
// this seems to only be needed on some devices before rotation? probably a bug
// uncomment the line below if needed on your device
// paddingTop: insets.top // <-- add padding to the top
}}
>
<Text style={style}>{text}</Text>
</View>
}
const App = () => (
<SafeAreaProvider>
<NavigationContainer >
<Stack.Navigator
screenOptions={{
headerStyle: {
backgroundColor: 'lightgreen',
},
headerTintColor: '#888',
headerTitleStyle: {
fontWeight: 'normal',
textAlign:'center',
},
}}
>
<Stack.Screen // 01 entrée
name={"E"}
component={EntreeScreen}
options={() => ({
headerLeft: () => ( // bouton aide
<Header text="LEFT" />
),
headerTitle: () => (
<Header style={{ textAlign: "center" }} text="MON TITRE!" />
),
headerRight: () => (
<Header text="RIGHT" />
),
})}
/>
</Stack.Navigator>
</NavigationContainer>
</SafeAreaProvider>
);
registerRootComponent(App);
I also wrote up an Expo Snack as a live demo: https://snack.expo.dev/@agilgur5/safe-area-edge-to-edge---so-question-79607558?platform=android. Here's a screenshot of the phone preview with the components fitting as desired with the top status bar, notch, and bottom navigation buttons: