Basar Sen
Basar Sen

Reputation: 359

React Native header / bottom tabbar jumping on first app load

I have a single application which includes only navigation packages. On IOS, all is fine but on Android, header and/or bottom tabbar seems like jumping (maybe recalculating their positions). This happens only when I use navigation components and only when app is just launched. Is there anyone faced same problem?

enter image description here

Thanks in advance.


Packages:

"@react-native-community/masked-view": "^0.1.10",
"@react-navigation/bottom-tabs": "^5.6.1",
"@react-navigation/native": "^5.6.1",
"@react-navigation/stack": "^5.6.2",
"react": "16.11.0",
"react-native": "0.62.2",
"react-native-gesture-handler": "^1.6.1",
"react-native-reanimated": "^1.9.0",
"react-native-safe-area-context": "^3.0.7",
"react-native-screens": "^2.9.0"

This is the whole app:

import * as React from 'react';
import { Button, Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

function DetailsScreen() {
    return (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
            <Text>Details!</Text>
        </View>
    );
}

function HomeScreen({ navigation }) {
    return (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
            <Text>Home screen</Text>
            <Button
                title="Go to Details"
                onPress={() => navigation.navigate('Details')}
            />
        </View>
    );
}

function SettingsScreen({ navigation }) {
    return (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
            <Text>Settings screen</Text>
            <Button
                title="Go to Details"
                onPress={() => navigation.navigate('Details')}
            />
        </View>
    );
}

const HomeStack = createStackNavigator();

function HomeStackScreen() {
    return (
        <HomeStack.Navigator>
            <HomeStack.Screen name="Home" component={HomeScreen} />
            <HomeStack.Screen name="Details" component={DetailsScreen} />
        </HomeStack.Navigator>
    );
}

const SettingsStack = createStackNavigator();

function SettingsStackScreen() {
    return (
        <SettingsStack.Navigator>
            <SettingsStack.Screen name="Settings" component={SettingsScreen} />
            <SettingsStack.Screen name="Details" component={DetailsScreen} />
        </SettingsStack.Navigator>
    );
}

const Tab = createBottomTabNavigator();

export default function App() {
    return (
        <NavigationContainer>
            <Tab.Navigator>
                <Tab.Screen name="Home" component={HomeStackScreen} />
                <Tab.Screen name="Settings" component={SettingsStackScreen} />
            </Tab.Navigator>
        </NavigationContainer>
    );
}

Upvotes: 22

Views: 7980

Answers (4)

Sagar
Sagar

Reputation: 59

give this

navigationOptions: {
        headerShown: true,
        safeAreaInsets: {
          top: 0,
          bottom: 0,
          left: 0,
          right: 0,
        },
      },

if you are using react-navigation 4x

Upvotes: 0

badsyntax
badsyntax

Reputation: 9650

I was struggling with this exact bug for a while. I've finally been able to find a workaround.

It seems that all the ReactNavigation navigators (eg Tab and Stack) will by default accommodate safe areas. This is mentioned in this page: https://reactnavigation.org/docs/bottom-tab-navigator/

By default, the device's safe area insets are automatically detected

So it seems the behaviour we're seeing is due to this. It's not clear why ReactNavigation has buggy "safe area" logic, but the workaround is to disable that.

The workaround is similar to what @Arun Girivasan has suggested, with a couple extra steps:

  1. Use react-native-safe-area-context to wrap everything in a SafeAreaProvider and SafeAreaView
  2. Specify the safeAreaInsets to be 0 for all directions:
<Tab.Navigator
  initialRouteName="AppDashboard"
  tabBarOptions={{
    safeAreaInsets: {
      top: 0,
      bottom: 0,
      left: 0,
      right: 0,
    }
  }}
>
  1. If you're creating stacks within your tab screens, provide the same safeAreaInsets for your stack navigators.

With these changes I'm no longer seeing the tab bar height jump AND i'm no longer seeing the stack header jumping. Basically this workaround resolves all UI glitches for me.

Upvotes: 11

Muhammad Shahzeb
Muhammad Shahzeb

Reputation: 11

same thing happend to me on @react-navigation/bottom-tabs i just removed paddingBottom and padding top from "tabstyle" and pasted in "style" this solved the issue

BEFORE:

  tabBarOptions={{
    keyboardHidesTabBar: true,
    activeTintColor: COLOR.white,

    style: {
      backgroundColor: COLOR.primary,
      height: responsiveHeight(7),
    },
    tabStyle: {
      paddingBottom: responsiveHeight(0.5),
      paddingTop: responsiveHeight(0.5),
    },
  }}

AFTER:

  tabBarOptions={{
    keyboardHidesTabBar: true,
    activeTintColor: COLOR.white,
    style: {
      backgroundColor: COLOR.primary,
      height: responsiveHeight(7),
      paddingBottom: responsiveHeight(0.5),
      paddingTop: responsiveHeight(0.5),
    },
  
  }}
...

i hope it helps :)

Upvotes: 1

Arun Girivasan
Arun Girivasan

Reputation: 602

I fixed this problem by using SafeAreaProvider. You should add SafeAreaProvider in your app root component and use SafeAreaView as the root component of your page. Also check the import statement of SafeAreaView , react-native also has SafeAreaView but that component only supports iOS 10+ .

Upvotes: 23

Related Questions