expoexpo-router

Weird top and bottom safe area insets in expo


Expo is adding padding to top and bottom weirdly. I don't even use SafeAreaView or useSafeAreaInsets etc.

I tried to wrap layout with View, SafeAreaProvider, SafeAreaContext with setting bgColor and flex:1 none of them worked. I inspected with React Devtools and i guess expo auto add SafeAreaProvider?

(I'm using expo router and don't use any ui library)

top: enter image description here

bottom: enter image description here

_layout.tsx:

<Tabs

        safeAreaInsets={{ top: 0, right: 0, bottom: 0, left: 0 }}
        screenOptions={{
          headerStatusBarHeight: 0,
          headerShown: false,
          tabBarStyle: {
            backgroundColor: Colors.primarySoft,
            borderTopLeftRadius: 30,
            borderTopRightRadius: 30,
            height: 25 + insets.bottom,
            paddingBottom: 0,
          },
          headerPressColor: Colors.orange,
          tabBarActiveTintColor: Colors.orange,
          tabBarInactiveTintColor: Colors.grey,
          tabBarLabelStyle: {
            fontFamily: Fonts.bold,
            fontSize: 12,
          },
        }}
      >
        <Tabs.Screen
          name="index"
          options={{
            title: "Home",
            tabBarIcon: ({ focused, color }) => (
              <Ionicons
                name={"home"}
                size={24}
                color={color}
              />
            ),
          }}
        />
        <Tabs.Screen
          name="leaderboard"
          options={{
            title: "Leaderboard",
            tabBarIcon: ({ focused, color }) => (
              <Ionicons
                name={"trophy"}
                size={24}
                color={color}
              />
            ),
          }}
        />
        <Tabs.Screen
          name="achievements"
          options={{
            title: "Achievements",
            tabBarIcon: ({ focused, color }) => (
              <Ionicons
                name={"medal"}
                size={24}
                color={color}
              />
            ),
          }}
        />
        <Tabs.Screen
          name="profile"
          options={{
            title: "Profile",
            tabBarIcon: ({ focused, color }) => (
              <Ionicons
                name={"person"}
                size={24}
                color={color}
              />
            ),
          }}
        />
      </Tabs>

index.tsx:

export default function HomeScreen() {
 const [selectedFriend, setSelectedFriend] = useState("1");

 return (
   <View style={styles.safeArea}>
     <ScrollView 
       style={styles.container}
       contentContainerStyle={styles.scrollContent}
     >
       {/* user info */}
       <View style={styles.userContainer}>
         <CustomText variant="bold" style={styles.welcomeText}>
           Welcome back,{"  "}Selçuk
         </CustomText>
       </View>
       {/* start play */}
       <View style={styles.startPlayContainer}>
         <View>
           <CustomText variant="bold" style={styles.startPlayText}>
             Start playing {"\n"}quiz now
           </CustomText>
           <TouchableOpacity onPress={()=>router.push("/game/create")} style={styles.startPlayButton}>
             <CustomText style={styles.startPlayButtonText}>Start</CustomText>
           </TouchableOpacity>
         </View>
         <Image
           style={styles.startPlayImage}
           resizeMode="cover"
           source={require("@/assets/images/home/3d_illustration_nature.png")}
         />
       </View>
       {/* friends */}
       <FriendList
         friends={friends}
         selectedFriend={selectedFriend}
         onSelectFriend={setSelectedFriend}
       />
       {/* discovery */}
       <Discovery />
     </ScrollView>
   </View>
 );
}

const styles = StyleSheet.create({
 container: {
   flex: 1,
   paddingHorizontal: 16,
 },
 safeArea: {
   flex: 1,
   backgroundColor: Colors.primary,
 },
 userContainer: {
   marginTop: 4,
 },
 welcomeText: {
   fontSize: 24,
   fontWeight: "500",
   color: Colors.black,
 },
 startPlayContainer: {
   flexDirection: "row",
   marginTop: 30,
   position: "relative",
   alignItems: "center",
   justifyContent: "space-between",
   gap: 8,
   backgroundColor: Colors.green,
   paddingHorizontal: 25,
   paddingVertical: 30,
   borderRadius: 16,
 },
 startPlayText: {
   fontSize: 18,
   fontWeight: "500",
   color: Colors.white,
 },
 startPlayImage: {
   width: 200,
   height: 200,
   position: "absolute",
   top: -20,
   right: 0,
 },
 startPlayButton: {
   borderWidth: 1,
   borderColor: Colors.white,
   padding: 5,
   borderRadius: 15,
   marginTop: 10,
 },
 startPlayButtonText: {
   fontSize: 14,
   fontWeight: "500",
   color: Colors.white,
   textAlign: "center",
 },
 scrollContent: {
   paddingBottom: 25,
 },
});

Solution

  • Added _layout.tsx to my app folder root. And below code.

    <Stack screenOptions={{ headerShown: false }} />
    

    this fixed my issue.