简体   繁体   English

React navigation 5 从堆栈导航器中隐藏标签栏

[英]React navigation 5 hide tab bar from stack navigator

I wanted to know how to hide the bottom tab bar from a specific screen inside my stack navigator that is nested on a material bottom tab bar我想知道如何从嵌套在材料底部标签栏上的堆栈导航器内的特定屏幕隐藏底部标签栏

This is my code for my stack navigator这是我的堆栈导航器代码

import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import PondScreen from '../screens/PondScreen/PondScreen';
import PondDetailScreen from '../screens/PondScreen/PondDetailScreen';

const Stack = createStackNavigator();

export function PondStack() {
  return (
    <Stack.Navigator
      initialRouteName="PondScreen"
      headerMode="none"
      mode="card"
    >
      <Stack.Screen
        name="PondScreen"
        component={PondScreen}
      />
      <Stack.Screen
        name="PondDetailScreen"
        component={PondDetailScreen}
        options={{
          tabBarVisible: false
        }}
      />
    </Stack.Navigator>
  );
}

This is my code for my material bottom tab navigator这是我的材料底部选项卡导航器的代码

import React from 'react';
import { View } from 'react-native';
import { createMaterialBottomTabNavigator } from '@react-navigation/material-bottom-tabs';
import { Entypo, Feather } from '@expo/vector-icons';
import { PondStack } from './StackNavigators';
import StockScreen from '../screens/StockScreen';
import OrderScreen from '../screens/OrderScreen';
import SettingsScreen from '../screens/SettingsScreen';

const Tab = createMaterialBottomTabNavigator();

export default function BottomTab() {
  return (
    <Tab.Navigator
      labeled={false}
      initialRouteName="Pond"
      activeColor="#EB3349"
      inactiveColor="#888888"
      backBehavior="none"
      shifting={true}
      barStyle={{
        backgroundColor: '#FFFFFF'
      }}
    >
      <Tab.Screen
        name="Pond"
        component={PondStack}
        options={{
          tabBarIcon: ({ color}) => (
            <View style={{ flex: 1 }}>
              <Entypo name="air" color={color} size={20} />
            </View>
          )
        }}
      />
      <Tab.Screen
        name="Stock"
        component={StockScreen}
        options={{
          tabBarIcon: ({ color }) => (
            <View style={{ flex: 1 }}>
              <Feather name="box" color={color} size={20} />
            </View>
          )
        }}
      />
      <Tab.Screen
        name="Order"
        component={OrderScreen}
        options={{
          tabBarIcon: ({ color}) => (
            <View style={{ flex: 1 }}>
              <Feather name="dollar-sign" color={color} size={20} />
            </View>
          )
        }}
      />
      <Tab.Screen
        name="Settings"
        component={SettingsScreen}
        options={{
          tabBarIcon: ({ color}) => (
            <View style={{ flex: 1 }}>
              <Feather name="settings" color={color} size={20} />
            </View>
          )
        }}
      />
    </Tab.Navigator>
  )
}

I am currently using Expo to build my project.我目前正在使用 Expo 来构建我的项目。

My dependencies (package.json)我的依赖项(package.json)

{
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "eject": "expo eject"
  },
  "dependencies": {
    "@react-native-community/masked-view": "^0.1.5",
    "@react-navigation/material-bottom-tabs": "^5.0.0",
    "@react-navigation/native": "^5.0.0",
    "@react-navigation/stack": "^5.0.0",
    "@types/react-native": "^0.61.12",
    "expo": "~36.0.0",
    "react": "~16.9.0",
    "react-dom": "~16.9.0",
    "react-native": "https://github.com/expo/react-native/archive/sdk-36.0.0.tar.gz",
    "react-native-gesture-handler": "~1.5.0",
    "react-native-paper": "^3.6.0",
    "react-native-raw-bottom-sheet": "^2.0.6",
    "react-native-reanimated": "~1.4.0",
    "react-native-safe-area-context": "0.6.0",
    "react-native-screens": "2.0.0-alpha.12",
    "react-native-vector-icons": "^6.6.0",
    "react-native-web": "~0.11.7"
  },
  "devDependencies": {
    "@babel/core": "^7.0.0",
    "babel-preset-expo": "~8.0.0"
  },
  "private": true
}

I had almost the same issue with a tabnavigation as parent and stacknavigation as childs and rearranging my screen layer wasn't an option.我在 tabnavigation 作为父级和 stacknavigation 作为孩子时遇到了几乎相同的问题,并且重新排列我的屏幕层不是一个选项。 So I looked for another solution and from the docs I found out that the parent navigation UI is always shown on the child.所以我寻找了另一种解决方案,从文档中我发现父导航 UI 总是显示在孩子身上。 But the docs also gave a great example on how to change a parent header from within a child.但是文档还提供了一个很好的示例,说明如何从子项中更改父标题。 So I took that example and implemented it for the tabbar visibility.所以我拿了这个例子并实现了它的标签栏可见性。 This is how I implemented it.这就是我实现它的方式。

So I have a tabbar navigation with Home, Contacts and More, and inside each tab I have a stack.所以我有一个带有主页、联系人等的标签栏导航,在每个标签内我都有一个堆栈。 The screen that I hide the tabbar in is in the CameraView, and that screen is a stackscreen in the More tab.我隐藏标签栏的屏幕在 CameraView 中,该屏幕是更多选项卡中的堆栈屏幕。

  • Home
  • Contacts联系人
  • More更多的
    • Profile轮廓
    • CameraView (here I want to hide the tabbar) CameraView(这里我想隐藏标签栏)

Tabnavigation:标签导航:

As you can see I get the visibility of the tabbar from a method.如您所见,我从一个方法中获得了标签栏的可见性。

<NavigationContainer>
  <Tab.Navigator>
    <Tab.Screen name="Home" component={HomeNavigation} />
    <Tab.Screen name="Contacts" component={ContactNavigation} />
    <Tab.Screen
      name="More"
      component={MoreNavigation}
      options={({ route }) => ({
        tabBarVisible: this.getTabBarVisibility(route)
      })}
    />
  </Tab.Navigator>
</NavigationContainer>

Method getTabBarVisibility:方法 getTabBarVisibility:

This is were I check if the name of the route is CameraView which I defined in the StackNavigation.这是我检查路线的名称是否是我在 StackNavigation 中定义的 CameraView。

getTabBarVisibility = (route) => {
  const routeName = route.state
    ? route.state.routes[route.state.index].name
    : '';

  if (routeName === 'CameraView') {
    return false;
  }

  return true;
}

And the component MoreNavigation:和组件 MoreNavigation:

This is my stacknavigation for More, where you can see that the screen name is CameraView.这是我对 More 的堆栈导航,可以看到屏幕名称是 CameraView。

<Stack.Navigator initialRouteName="More">
  <Stack.Screen name="More" component={More}/>
  <Stack.Screen name="UserProfile" component={Profile}/>
  <Stack.Screen name="CameraView" component={CameraView}/>
</Stack.Navigator>

You should try to rearrange your screen layer,你应该尝试重新排列你的屏幕层,

Original原来的

  • TabBar标签栏
    • Pond(Stack)池塘(堆叠)
      • PondScreen池塘屏风
      • DetailScreen详细画面
    • Stock库存
    • Others其他

Instead, try to set a top stack over相反,尝试设置顶部堆栈

  • TopStack顶栈
    • TabBar标签栏
      • PondScreen池塘屏风
      • Stock库存
      • Others其他
    • Details细节

That should be able to hide the bottom tab bar or tab header in each screen那应该能够隐藏每个屏幕中的底部标签栏或标签标题

The accepted answer is great, but you might want to do it inline, and use the getFocusedRouteNameFromRoute to be safe.接受的答案很好,但您可能希望内联进行,并使用getFocusedRouteNameFromRoute以确保安全。 This code does the same as the accepted answer:此代码与接受的答案相同:

<Tabs.Screen
    name="Home"
    component={HomeStack}
    options={({ route }) => ({
        tabBarVisible: ((route) => {
            const routeName = getFocusedRouteNameFromRoute(route) ?? ""

            if (routeName === "CameraView") {
                return false
            }

            return true
        })(route),
    })}
/>

The trick is to add the TabsStack, OtherStack or SomeOtherScreen inside your诀窍是将 TabsStack、OtherStack 或 SomeOtherScreen 添加到您的

<Stack.Navigator /> via a <Stack.Screen /> <Stack.Navigator />通过<Stack.Screen />

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="TabsStack" component={TabsStack} />
        <Stack.Screen name="SomeOtherScreen" component={SomeOtherScreen} />
        <Stack.Screen name="OtherStack" component={OtherStack} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

it is documented over here它记录在这里

Add this function for hiding the bottom bar in MyTabBar在 MyTabBar 中添加隐藏底部栏的功能

const focusedOptions = descriptors[state.routes[state.index].key].options;
if (focusedOptions.tabBarVisible === false) {
  return null;
}

MyTabBar我的标签栏

    import { View, Text, TouchableOpacity } from 'react-native';

    function MyTabBar({ state, descriptors, navigation }) {
      const focusedOptions = descriptors[state.routes[state.index].key].options;

      if (focusedOptions.tabBarVisible === false) {
        return null;
      }

      return (
        <View style={{ flexDirection: 'row' }}>
          {state.routes.map((route, index) => {
            const { options } = descriptors[route.key];
            const label =
              options.tabBarLabel !== undefined
                ? options.tabBarLabel
                : options.title !== undefined
                ? options.title
                : route.name;

            const isFocused = state.index === index;

            const onPress = () => {
              const event = navigation.emit({
                type: 'tabPress',
                target: route.key,
                canPreventDefault: true,
              });

              if (!isFocused && !event.defaultPrevented) {
                navigation.navigate(route.name);
              }
            };

            const onLongPress = () => {
              navigation.emit({
                type: 'tabLongPress',
                target: route.key,
              });
            };

            return (
              <TouchableOpacity
                accessibilityRole="button"
                accessibilityStates={isFocused ? ['selected'] : []}
                accessibilityLabel={options.tabBarAccessibilityLabel}
                testID={options.tabBarTestID}
                onPress={onPress}
                onLongPress={onLongPress}
                style={{ flex: 1 }}
              >
                <Text style={{ color: isFocused ? '#673ab7' : '#222' }}>
                  {label}
                </Text>
              </TouchableOpacity>
            );
          })}
        </View>
      );
    }

add bottom bar visibility in screen stack在屏幕堆栈中添加底部栏可见性

    const getTabBarVisibility = (route) => {
      const routeName = route.state
        ? route.state.routes[route.state.index].name
        : '';

      if (routeName === 'Profile') {
        return false;
      }

      return true;
    };

Add options in main tab navigators在主选项卡导航器中添加选项

    const MainAppNavigator = ({userToken}) => {
      return (
        <NavigationContainer>
          {!userToken ? (
            <AuthNavigator />
          ) : (
              <Tab.Navigator tabBar={(props) => <MyTabBar {...props} />}>
              <Tab.Screen
                name={'Dashboard'}
                component={DashboardStackScreen}
              />
              <Tab.Screen
                name={'More'}
                component={MoreStackScreen}
                options={({route}) => ({
                  tabBarVisible: getTabBarVisibility(route),
                })}
              />
            </Tab.Navigator>

          )}
        </NavigationContainer>
      );
    };

Add Profile screen in More Stack在更多堆栈中添加配置文件屏幕

  const MoreStack = createStackNavigator();

  export default class MoreStackScreen extends React.Component {
    render() {
      return (
        <MoreStack.Navigator initialRouteName={'More'}>
          <MoreStack.Screen
            name={'More'}
            component={More}
          />
          <MoreStack.Screen
            name={'Profile'}
            component={Profile}
          />
        </MoreStack.Navigator>
      );
    }
  }

You don't need to use Keyboard listeners and change your AndroidManifest.xml file you can solve this issue by just adding this tabBarOptions props :您不需要使用键盘侦听器并更改您的 AndroidManifest.xml 文件,只需添加此 tabBarOptions 道具即可解决此问题:

 <Tab.Navigator

 tabBarOptions={{

keyboardHidesTabBar: true,

 }}>

 </Tab.Navigator>

Tabbarvisible property didn't work for me and I made a small workaround. Tabbarvisible 属性对我不起作用,我做了一个小的解决方法。 It includes ReactContext + Hoc.它包括 ReactContext + Hoc。

  1. First thing we need to do is to create a react context with two fields visible and setVisible我们需要做的第一件事是创建一个具有可见和 setVisible 两个字段的反应上下文

 export const TabBarVisibilityContext = React.createContext({ visible: false, setVisible: () => { }, });
2) Then we will create a hoc that will wrap a tab navigator component. 2) 然后我们将创建一个 hoc 来包装一个选项卡导航器组件。

 export const TabBarHidable = (Component) => (props) => { const [visible, setVisible] = useState(true); return ( <TabBarVisibilityContext.Provider value={{ visible, setVisible }}> <Component {...props} /> </TabBarVisibilityContext.Provider> ); };

  1. Apply hoc for tab navigator component and extract a visible property from the context.对选项卡导航器组件应用 hoc 并从上下文中提取可见属性。

 const { visible, setVisible } = useContext(TabBarVisibilityContext);

  1. Update properties in tab navigator options tabBarOptions = {{ style: { transform: !visible ?更新选项卡导航器选项中的属性 tabBarOptions = {{ style: { transform: !visible ? [{ scale: 0 }] : [], }} [{ scale: 0 }] : [], }}

  2. Use setVisible from context to make the tabbar hidden.使用上下文中的 setVisible 隐藏标签栏。

 const { setVisible } = useContext(TabBarVisibilityContext); useEffect(() => { setVisible(false); return () => setVisible(true); , []})

Hope it will help someone to save his/her time.希望它会帮助某人节省他/她的时间。 I haven't found an appropriate and concise solution to the given problem.我还没有找到针对给定问题的适当且简洁的解决方案。

I am using typescript and I encountered such an issue too.我正在使用打字稿,我也遇到了这样的问题。 Since the tabBarVisible option is no longer available, I used the tabBarStyle instead and set the display property to 'none'.由于 tabBarVisible 选项不再可用,我改用 tabBarStyle 并将显示属性设置为“无”。

Suppose I have two screens, the Home screen which is the tabbed screen and another screen say Side screen which is a Stacked screen where I want to hide the tab bar, then I do this in the Stacked screen navigator component:假设我有两个屏幕,主屏幕是选项卡式屏幕,另一个屏幕说侧屏幕是我想隐藏标签栏的堆叠屏幕,然后我在堆叠屏幕导航器组件中执行此操作:

const setTabStyleVisibility = (shouldBeVisible: boolean) =>
shouldBeVisible
  ? ({
      tabBarStyle: { display: 'flex' },
    } as Partial<BottomTabNavigationOptions>)
  : ({
      tabBarStyle: { display: 'none' },
    } as Partial<BottomTabNavigationOptions>);

I have a custom button defined as:我有一个自定义按钮定义为:

<Button title={btnTitle} onPress={onPressHandler}/>

On the Home Screen, I have a button which navigates to the Side screen and hides the tab by defining the custom onPressedHandler prop to the custom button as:在主屏幕上,我有一个按钮可以导航到侧屏幕并通过将自定义 onPressedHandler 属性定义为自定义按钮来隐藏选项卡:

onPressHandler={() => {
    navigation.setOptions({
      ...setTabStyleVisibility(false),
    });
    navigation.navigate("Side");
  }}

Then I had a button passed to the next screen (Side screen) where the tab bar will be shown on going back to Home screen.然后我有一个按钮传递到下一个屏幕(侧屏),在返回主屏幕时将显示标签栏。 I set the onPressedHandler which is a custom prop to the custom button to我将作为自定义道具的 onPressedHandler 设置为自定义按钮

onPressHandler={() => {
    navigation.setOptions({
      ...setTabStyleVisibility(true),
    });
    navigation.navigate("Home");
  }}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM