react-navigation / react-navigation

Routing and navigation for your React Native apps
https://reactnavigation.org
23.59k stars 5.04k forks source link

Hide tabbar in specific screen #7464

Closed alikazemkhanloo closed 4 years ago

alikazemkhanloo commented 6 years ago

I want to hide tabbar when I reached a screen deep in the stackNavigator. my routes are something like this:

materialTabNavigator:{ Homestack:{ Homescreen, Detailscreen }, Librarystack: {
Libraryscreen, Detailscreen } } and I want to hide the tabbar when I reach the Detailscreen. when I use tabBarVisible in Homestack it works fine, But using it in Detailscreen, doesn't. In react-navigation/material-bottom-tabs#20, we can only hide tabbar, if we are in the direct child of tab navigator. But if you go deeper, you can't. I think this option must be passed all the way to top in the navigation tree 🤔

koo27 commented 5 years ago

I found a solution for that, it works perfectly: https://reactnavigation.org/docs/en/navigation-options-resolution.html#a-tab-navigator-contains-a-stack-and-you-want-to-hide-the-tab-bar-on-specific-screens

Basically you set on your Homestack as following:

Homestack.navigationOptions = ({ navigation }) => {
  let tabBarVisible = true;
  if (navigation.state.index > 0) {
    tabBarVisible = false;
  }

  return {
    tabBarVisible,
  };
};

edit

I actually just found out that the above method is useful to hide the tabBar in all the "children" screens of your main stack. That means that if you want to hide the tabbar for a specific route you can add this condition in the inner if statement navigation.state.routes[1].routeName === "Detailscreen"

So the final code would be:

Homestack.navigationOptions = ({ navigation }) => {
  let tabBarVisible = true;
  if (navigation.state.index > 0 && navigation.state.routes[1].routeName === "Detailscreen") {
    tabBarVisible = false;
  }

  return {
    tabBarVisible,
  };
};

I know it's a bit tricky as a solution, but it's the only thing that I came up with so far. Hope it helps

edit 2: new version

Homestack.navigationOptions = ({ navigation }) => {
    let tabBarVisible = navigation.state.routes[navigation.state.index].params.showTabBar; 

    return {
      tabBarVisible,
    };
};

It's a more elegant solution. In this case you don't have to hardcode the name of the screen, but just use a custom param "showTabBar" (for example) in your screens and set it to true or false depening on where you want to show/hide the tab bar.

baudev commented 5 years ago

The recommended way is the following one:

Another option here would be to add another stack navigator as a parent of the tab navigator, and put the details screen there. This is recommended.

const FeedStack = createStackNavigator({
  FeedHome: FeedScreen,
  /* any other route you want to render under the tab bar */
});

const TabNavigator = createBottomTabNavigator({
  Feed: FeedStack,
  Profile: ProfileScreen,
});

const HomeStack = createStackNavigator({
  Tabs: TabNavigator,
  Details: DetailsScreen,
  /* any other route you want to render above the tab bar */
});

const AppNavigator = createSwitchNavigator({
  Auth: AuthScreen,
  Home: HomeStack,
});

Source: https://reactnavigation.org/docs/en/navigation-options-resolution.html#a-tab-navigator-contains-a-stack-and-you-want-to-hide-the-tab-bar-on-specific-screens

alikazemkhanloo commented 5 years ago

Thanks, guys. Seems the issue is resolved.

Salahudin31 commented 5 years ago

Thanks, baudev.

ilibilibom commented 4 years ago

Hi This is not working for me. I'm using react-navigation v5 It's not even getting into the function since I don't see any console.log() here is my code:

function homeStack() {
  return (
    <Stack.Navigator>
      <Stack.Screen
        name="Home"
        component={Home}
        options={{
          header: null,
        }}
      />

      <Stack.Screen
        name="Item"
        component={Item}
        options={{
          title: '',
        }}
      />
    </Stack.Navigator>
  );
}

homeStack.navigationOptions = ({navigation}) => {
  let tabBarVisible = true;
  console.log('navigation.state.routes[1].routeName', navigation);
  if (
    navigation.state.index > 0 &&
    navigation.state.routes[1].routeName === 'Item'
  ) {
    tabBarVisible = false;
  }

  return {
    tabBarVisible,
  };
};
ilibilibom commented 4 years ago

Here is a repro for my issue stated above https://snack.expo.io/@ilandiam/smiling-bananas please assist!

Temirtator commented 4 years ago

Hi This is not working for me. I'm using react-navigation v5 It's not even getting into the function since I don't see any console.log() here is my code:

function homeStack() {
  return (
    <Stack.Navigator>
      <Stack.Screen
        name="Home"
        component={Home}
        options={{
          header: null,
        }}
      />

      <Stack.Screen
        name="Item"
        component={Item}
        options={{
          title: '',
        }}
      />
    </Stack.Navigator>
  );
}

homeStack.navigationOptions = ({navigation}) => {
  let tabBarVisible = true;
  console.log('navigation.state.routes[1].routeName', navigation);
  if (
    navigation.state.index > 0 &&
    navigation.state.routes[1].routeName === 'Item'
  ) {
    tabBarVisible = false;
  }

  return {
    tabBarVisible,
  };
};

i think u need to create another stackNavigator, out of bottomNavigator, then reference all u're screen, in that way.

UmerHayyat54 commented 4 years ago

example like this :

const AppStack = createStackNavigator({ SplashScreen: { screen: SplashScreen, navigationOptions: { header: null, }, }, Home: Home, CarouselMap: CarouselMap, HeatMapComponent: HeatMapComponent, });

pyxploiter commented 4 years ago

Hi This is not working for me. I'm using react-navigation v5 It's not even getting into the function since I don't see any console.log() here is my code:

function homeStack() {
  return (
    <Stack.Navigator>
      <Stack.Screen
        name="Home"
        component={Home}
        options={{
          header: null,
        }}
      />

      <Stack.Screen
        name="Item"
        component={Item}
        options={{
          title: '',
        }}
      />
    </Stack.Navigator>
  );
}

homeStack.navigationOptions = ({navigation}) => {
  let tabBarVisible = true;
  console.log('navigation.state.routes[1].routeName', navigation);
  if (
    navigation.state.index > 0 &&
    navigation.state.routes[1].routeName === 'Item'
  ) {
    tabBarVisible = false;
  }

  return {
    tabBarVisible,
  };
};
function homeStack({route, navigation}) {
  try {
    let tabBarVisible = true
    if (route.state.index > 0 && route.state.routes[1].name === "Item"){
      tabBarVisible = false
    }
    navigation.setOptions({
      tabBarVisible: tabBarVisible
    })
  } catch {
    console.log("route state is undefined")
  }

  return (
    <Stack.Navigator>
      <Stack.Screen
        name="Home"
        component={Home}
        options={{
          header: null,
        }}
      />

      <Stack.Screen
        name="Item"
        component={Item}
        options={{
          title: '',
        }}
      />
    </Stack.Navigator>
  );
}

This works for react-navigation v5

bazinga012 commented 3 years ago

Get the RootNavigation ref following approach given in: https://reactnavigation.org/docs/navigating-without-navigation-prop/

Define one more function in RootNavigation:

export function getCurrentLeafRoute() {
  if (isReadyRef.current && navigationRef.current) {
    return navigationRef.current.getCurrentRoute().name;
  }
}

Now we can use this method like this

import * as NavigationHelper from RootNavigation
// screensWithoutBottomBar = [ 'S1', 'S2' ]
// While setting TabNavigator tabBarVisible
tabBarVisible: screensWithoutBottomBar.indexOf(NavigationHelper.getCurrentLeafRoute()) !== -1
FaysalBsata commented 3 years ago

The flow goes like this

import {
  getFocusedRouteNameFromRoute,
} from "@react-navigation/native";
<BottomTab.Navigator
      screenOptions={(props) => {
        console.log(getFocusedRouteNameFromRoute(props.route));
        return {
          tabBarActiveTintColor: Colors.Red,
          tabBarInactiveTintColor: Colors.Blue,
          headerShown: false,
          tabBarStyle: {
            display:
              getFocusedRouteNameFromRoute(props.route) === "ProdDetails"
                ? "none"
                : "flex",
          },
        };
      }}
    >
{...children}
</BottomTab.Navigator>

Cheers

github-actions[bot] commented 3 years ago

Hey! This issue is closed and isn't watched by the core team. You are welcome to discuss the issue with others in this thread, but if you think this issue is still valid and needs to be tracked, please open a new issue with a repro.

Aszurar commented 2 years ago

The recommended way is the following one:

Another option here would be to add another stack navigator as a parent of the tab navigator, and put the details screen there. This is recommended.

const FeedStack = createStackNavigator({
  FeedHome: FeedScreen,
  /* any other route you want to render under the tab bar */
});

const TabNavigator = createBottomTabNavigator({
  Feed: FeedStack,
  Profile: ProfileScreen,
});

const HomeStack = createStackNavigator({
  Tabs: TabNavigator,
  Details: DetailsScreen,
  /* any other route you want to render above the tab bar */
});

const AppNavigator = createSwitchNavigator({
  Auth: AuthScreen,
  Home: HomeStack,
});

Source: https://reactnavigation.org/docs/en/navigation-options-resolution.html#a-tab-navigator-contains-a-stack-and-you-want-to-hide-the-tab-bar-on-specific-screens

Thaaaaannnnnnkss!!! solved for meeee!!!