React Navigation如何从堆栈导航中隐藏标签栏

时间:2018-07-15 20:41:53

标签: react-native react-navigation

我有以下堆栈导航和屏幕:

export const HomeStack = createStackNavigator({
    Home: HomeScreen,
    Categories: CategoriesScreen,
    Products: ProductsScreen,
    ProductDetails: ProductDetailsScreen,
})

我只想在ProductDetailsS​​creen中隐藏选项卡

export const hideTabBarComponents = [
    'ProductDetails',
]

export const MainTabs = createBottomTabNavigator(
    {
        Home: HomeStack,
        Favorite: FavoriteScreen,
        Account: AccountScreen,
        Help: HelpScreen,
        Events: EventsScreen
    },
    {
        navigationOptions: ({ navigation }) => ({

            tabBarIcon: ({ focused, tintColor }) => {
                ...
            },
            tabBarLabel: ({ focused, tintColor }) => {
                ...
            },

            tabBarVisible: ! hideTabBarComponents.includes(navigation.state.routeName)

        }),
    }
);

无法从堆栈导航将任何选项传递给Tab导航的问题

并非所有堆栈屏幕都只有其中之一

17 个答案:

答案 0 :(得分:16)

对于React Navigation 5,您可以在堆栈组件内部执行此操作:

props.navigation.dangerouslyGetParent().setOptions({
  tabBarVisible: false
});

https://reactnavigation.org/docs/en/navigation-prop.html#setoptions---update-screen-options-from-the-component

但是请谨慎使用,卸载组件后,您需要将tabBarVisible重置为true。

例如,在Stack组件内部使用React钩子:

    useEffect(() => {
      const parent = props.navigation.dangerouslyGetParent();
      parent.setOptions({
        tabBarVisible: false
      });
      return () =>
        parent.setOptions({
          tabBarVisible: true
        });
    }, []);

或者您可以按如下所示的向后按钮来重置Stack.Screen组件中的tabBarVisible:

    const StackNav = (props) => (
      <Stack.Screen
        name='name'
        component={Name}
        options={{
          headerTitle: 'Name',
          headerLeft: () => (
            <Text
              onPress={() =>
                props.navigation.setOptions({
                tabBarVisible: true
                })
              }
            >
              on back
            </Text>
          )
        }}
      />
    }

(第二种方法效果更好。)

答案 1 :(得分:9)

稍作搜索后,以下代码解决了该问题:

HomeStack.navigationOptions = ({ navigation }) => {

    let tabBarVisible = true;

    let routeName = navigation.state.routes[navigation.state.index].routeName

    if ( routeName == 'ProductDetails' ) {
        tabBarVisible = false
    }

    return {
        tabBarVisible,
    }
}

答案 2 :(得分:5)

这是我如何在堆栈中的特定屏幕(Reacat Nav 5.x)中隐藏选项卡栏的方法

enter image description here

import { getFocusedRouteNameFromRoute } from '@react-navigation/native';
const ProfileStack = createStackNavigator();
    
const ProfileNavigator = ({ navigation, route }) => {
        React.useLayoutEffect(() => {
            const routeName = getFocusedRouteNameFromRoute(route);
            if (routeName === "Group"){
                navigation.setOptions({tabBarVisible: false});
            }else {
                navigation.setOptions({tabBarVisible: true});
            }
        }, [navigation, route]);
        return(
            <ProfileStack.Navigator screenOptions={{headerShown: false}}>
                <ProfileStack.Screen name="Profile" component={ProfileScreen} />
                <ProfileStack.Screen name="Group" component={GroupScreen} />
            </ProfileStack.Navigator>
        )};

如果你们有很多需要隐藏标签栏的屏幕,请使用这些路由名称的字符串数组,如果该路由名称中包含焦点路由名称,则隐藏标签栏

const tabHiddenRoutes = ["Group","Map"];

if(tabHiddenRoutes.includes(getFocusedRouteNameFromRoute(route))){
  navigation.setOptions({tabBarVisible: false});
 }else{
 navigation.setOptions({tabBarVisible: true});
}

答案 3 :(得分:2)

首先,我们创建一个堆栈导航器并将其命名为StackHome

const StackHome = createStackNavigator(
{
 Home: Home,
 CustomHide: CustomHide,
});
// This code let you hide the bottom app bar when "CustomHide" is rendering
StackHome.navigationOptions = ({ navigation }) => {
 let tabBarVisible;
  if (navigation.state.routes.length > 1) {
navigation.state.routes.map(route => {
  if (route.routeName === "CustomHide") {
    tabBarVisible = false;
  } else {
    tabBarVisible = true;
  }
});
 }

 return {
   tabBarVisible
 };
};
export default StackHome;

答案 4 :(得分:2)

const AppNavigation = createBottomTabNavigator( {

    Learning:
    {
        screen: LearningStack,
        navigationOptions: {
            tabBarLabel: 'Learning',
            // tabBarVisible: false,
            tabBarIcon: ({ tintColor, focused }) => (
                // <Icon name='terminal' size={25} color={Colors.white} />
                <Image
                    source={require('../assets/TabBarIcon/Learning_96px.png')}
                    style={{ width: 45, height: '90%', }}
                />
            ),

        }
    },

学习

Stack.navigationOptions

=({导航})=> {

    let tabBarVisible = false;

    let routeName = navigation.state.routes[navigation.state.index].routeName

    if (routeName == 'Learning') {
        tabBarVisible = true
    }

    return {
        tabBarVisible
    }
},

})

答案 5 :(得分:1)

使用createBottomTabNavigator,您可以使用defaultNavigationOptions将其隐藏

defaultNavigationOptions: {
  tabBarVisible: false,
},

答案 6 :(得分:1)

我就是通过这种方式实现的。首先是钩子:

import {useLayoutEffect} from 'react';
import {useNavigation, useRoute, getFocusedRouteNameFromRoute} from '@react-navigation/native';

export function useHiddenTabs (hiddenTabRoutesArray, fallbackRoute) {
  const navigation = useNavigation();
  const route = useRoute();

  useLayoutEffect(() => {
    const routeName = getFocusedRouteNameFromRoute(route) ?? fallbackRoute;
    navigation.setOptions({
      tabBarVisible: !hiddenTabRoutesArray.includes(routeName),
    })
  }, [navigation, route]);
}

然后是用法:

import {getFocusedRouteNameFromRoute} from '@react-navigation/native';

const routesWithoutTabs = ['ScreenWithoutTabs'];

const StackComponent = ({navigation}) => {

  useHiddenTabs(routesWithHiddenTabs, 'FallbackRoute');

  return (
    <Stack.Navigator /* other props */>
      <Stack.Screen
        name='ScreenWithoutTabs'
        component={ScreenWithoutTabsComponent}
      />
    </Stack.Navigator>
  );
};

Corresponding docs

答案 7 :(得分:1)

另一种方法是使用标签栏的高度将其隐藏。使用createMaterialTopTabNavigator时,这是必需的,因为它没有tabBarVisible属性。您可以使用全局状态变量(Redux或UseState),也可以使用与所选答案类似的内容来跟踪当前活动的屏幕。

假设“ hideTab”是布尔值。

const Tab = createMaterialTopTabNavigator();
...
<Tab.Navigator
   tabBarOptions={{style: {height: hideTab ? '0%' : null}}>

答案 8 :(得分:0)

您还可以在屏幕内部创建模态,并使其始终可见,如下所示:

const Example = () => {
  return(
    <ScrollView>
      <Modal animationType="slide" transparent={true} visible={true} >
          <View style={styles.modalExample}>
          </View>
      </Modal> 
    </ScrollView>
  )
}

然后设置样式:

const styles = StyleSheet.create({
  modalExample: {
    height:"100%",
    width:"100%",
    backgroundColor: "#000000",
  },
})

答案 9 :(得分:0)

import React, {useLayoutEffect} from "react";
import { getFocusedRouteNameFromRoute } from '@react-navigation/native';

const MainStackNavigator = ({navigation, route}) => {
    useLayoutEffect(() => {
        const routeName = getFocusedRouteNameFromRoute(route);
        if (routeName === 'Details') {
            navigation.setOptions({tabBarVisible: false});
        }else {
            navigation.setOptions({tabBarVisible: true});
        }
    }, [navigation, route])

答案 10 :(得分:0)

您可以使用 useFocusEffect 钩子检查屏幕是否聚焦,然后使用 navigation.dangerouslyGetParent()

隐藏导航器

这是我创建的自定义钩子:

import React from 'react';
import { useFocusEffect } from '@react-navigation/native';

const useHideTabBar = (navigation) => {

    useFocusEffect(
        React.useCallback(() => {

            // hide
            const parent = navigation.dangerouslyGetParent();
            parent.setOptions({
                tabBarVisible: false,
            });

            // reveal after changing screen
            return () =>
                parent.setOptions({
                    tabBarVisible: true,
                });

        }, []),
    );


};

export default useHideTabBar;

答案 11 :(得分:0)

试试这个代码,它会起作用:

  const getTabBarVisibility = (route) => {
const routName = route.state
  ? route.state.routes[route.state.index].name
  : '';
if (routName == 'chat') {
  return false;
} else {
  return true;
}

};

答案 12 :(得分:0)

在 v5 中有多种方法可以做到: 1.根据特定的字符串/路由名称

使用tabBarVisible选项

using the useRoute() hook & setOptions({ tabBarVisible: false })

2.使用dangerouslyGetParent()方法进行动态控制 针对特定屏幕

navigation.dangerouslyGetParent()?.setOptions({ tabBarVisible: false })

滚动时隐藏底部标签栏

const navigation = useNavigation();

const handleScroll = ({ nativeEvent: { contentOffset: { y = 0 }} }) => {
  navigation.dangerouslyGetParent()?.setOptions({ tabBarVisible: y <= 50 })
}

return (
  <ScrollView onScroll={handleScroll} scrollEventThrottle={16}>
    ...
  </ScrollView>
)

3.为了简单的嵌套,您可以将“标签栏导航”传递给任何堆栈屏幕道具

// navigation -> is the bottomTab navigation instance
export default ({ navigation }) => {
  return (
    <Stack.Navigator screenOptions={screenOptions}>
      <Stack.Screen name="Trips">
        // add a new prop named tabNavigation={navigation}
        // you also have access to the stack navigation
        {(props) => <Trips tabNavigation={navigation} {...props} />}
      </Stack.Screen>
      <Stack.Screen name="Trip" component={Trip} />
    </Stack.Navigator>
  );
}

并使用第 2 点中的示例

tabNavigation?.setOptions({ tabBarVisible: false })

答案 13 :(得分:0)

这里的另一个选项是添加另一个堆栈导航器作为选项卡导航器的父级,然后将不需要选项卡导航器的屏幕放在此处。这是React Navigation <5

版本中的推荐方法
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,
});

答案 14 :(得分:0)

这是我在项目中使用的解决方案。

我有一个底部标签导航器,有2条路线:“首页”和“个人资料”。 ProfileHomePage路由将带到堆栈导航ProfileStackNavigation。

然后,在ProfileStackNavigation中,我有ProfileHomePage(应该在其中显示底部选项卡)和其他子页面(在其中不显示底部选项卡)。我在这些页面中添加了一个参数tabBarVisible: false

最后,在MainTabNavigator ProfileHomePage路由中,我添加了navigationOptions函数,以测试当前路由是否具有参数tabBarVisible。

const ProfileStackNavigation = createStackNavigator(
  {
    ProfileHomePage: ProfileHomePage,
    AboutAppPage: {screen: AboutAppPage, params: {tabBarVisible: false}},
    DiaryPage: {screen: DiaryPage, params: {tabBarVisible: false}},
    FilesPage: {screen: FilesPage, params: {tabBarVisible: false}},
    NotificationsPage: {screen: NotificationsPage, params: {tabBarVisible: false}},
  },
  {
    initialRouteName: 'ProfileHomePage',
  },
);

const MainTabNavigator = createBottomTabNavigator(
  {
    HomePage: HomePage,
    ProfileHomePage: {
      screen: ProfileStackNavigation,
      navigationOptions: ({ navigation }) => {
        const {params = {}} = navigation.state.routes[navigation.state.index];
        const tabBarVisible = params.tabBarVisible === false ? params.tabBarVisible : true;
        return {
          tabBarVisible,
        }
      }
    },
  },
  {
    initialRouteName: 'HomePage',
    tabBarComponent: props => <AppFooterTab {...props} />,
  },
);

答案 15 :(得分:0)

这就是我的做法。选择要在其中隐藏选项卡栏的堆栈。您可以根据索引选择它。

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

这是React导航docs的链接

答案 16 :(得分:-1)

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