反应导航5从堆栈导航器中隐藏标签栏

Posted

技术标签:

【中文标题】反应导航5从堆栈导航器中隐藏标签栏【英文标题】:React navigation 5 hide tab bar from stack navigator 【发布时间】:2020-05-27 08:16:18 【问题描述】:

我想知道如何从嵌套在材质底部标签栏上的堆栈导航器内的特定屏幕中隐藏底部标签栏

这是我的堆栈导航器代码

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>
  );

这是我的材料底部标签导航器的代码

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>
  )

我目前正在使用 Expo 来构建我的项目。

我的依赖项(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

【问题讨论】:

对于您的下一个问题,您可能希望使用 react-navigation 标记您的问题,以便更多人可以看到它。 【参考方案1】:

你应该尝试重新排列你的屏幕层,

原创

标签栏 池塘(栈) 池屏 详细画面 库存 其他

相反,尝试设置一个顶部堆栈

顶栈 标签栏 池屏 库存 其他 详情

那应该可以在每个屏幕中隐藏底部标签栏或标签标题

【讨论】:

这应该是公认的答案,因为它是文档推荐的答案。 知道如何处理多个堆栈吗?通过选项卡导航后的另一个堆栈? 如果您有嵌套堆栈,只需将其放在最低的一个。这就是它对我有用的方式。在那里,我用 TabBar nav 替换了 home 组件。【参考方案2】:

我遇到了几乎相同的问题,即 tabnavigation 作为 parent 和 stacknavigation 作为 childs 并且重新排列我的屏幕层不是一个选项。所以我寻找了另一种解决方案,从docs 我发现父导航 UI 总是显示在孩子身上。 但是docs 也提供了一个很好的例子,说明如何从孩子内部更改父标题。所以我举了这个例子并为标签栏的可见性实现了它。我就是这样实现的。

所以我有一个带有主页、联系人和更多的标签栏导航,并且在每个标签内我都有一个堆栈。我隐藏标签栏的屏幕位于 CameraView 中,该屏幕是更多标签中的堆栈屏幕。

首页 联系方式 更多
简介 CameraView(这里我要隐藏tabbar)

标签导航:

如您所见,我从方法中获得了标签栏的可见性。

<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>

方法 getTabBarVisibility:

这是我检查路线的名称是否是我在 StackNavigation 中定义的 CameraView。

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

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

  return true;

还有MoreNavigation组件:

这是我的更多堆栈导航,您可以在其中看到屏幕名称是 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>

【讨论】:

文档建议不要使用这种方法,因为它会导致页脚组件出现故障动画。我建议不要使用这种方法,而是像文档suggests 那样重新组织您的页面。 @EricWiener 文档最近更新了,我在文档更新之前给出了这个答案。我们的应用程序没有遇到任何故障。因此我们坚持这个解决方案并且不会重新组织我们的页面,虽然有一个你不使用的额外堆栈是很奇怪的,只是为了隐藏一个底部栏。顺便说一句,如果您想以不同的方式设置标题,他们建议使用这种方法.... @Emmie 明白了。谢谢你让我知道。你的回答肯定能完成工作,但对我来说,它导致标签栏在导航到新页面之前过早消失。 @EricWiener 很高兴知道,当我们遇到故障问题时,我们会对此进行调查。 使用: const routeName = getFocusedRouteNameFromRoute(route);避免错误:不支持访问“路由”对象的“状态”属性。如果您想获取焦点路由名称,请改用“getFocusedRouteNameFromRoute”帮助器:reactnavigation.org/docs/screen-options-resolution/…【参考方案3】:

诀窍是在你的

中添加 TabsStack、OtherStack 或 SomeOtherScreen

&lt;Stack.Navigator /&gt; 通过&lt;Stack.Screen /&gt;

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>
  );

它记录在here

【讨论】:

谢谢卢克。带有示例代码的好答案,它可以工作 我以前在 Navigation4.x 上有这个,但在 5 中,一切都像新的一样,所以我很想念这个。这是作品 谢谢,这是最好的解决方案,您可以只显示 TabsStack 标题并使用 options= headerShown: false 隐藏“Stack.Screen”,如下所示:【参考方案4】:

在MyTabBar中添加隐藏底部栏的功能

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

我的标签栏

    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>
      );
    

在屏幕堆栈中添加底部栏可见性

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

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

      return true;
    ;

在主选项卡导航器中添加选项

    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>
      );
    ;

在更多堆栈中添加配置文件屏幕

  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>
      );
    
  

【讨论】:

【参考方案5】:

公认的答案很好,但您可能希望内联,并使用getFocusedRouteNameFromRoute 以确保安全。此代码与接受的答案相同:

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

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

            return true
        )(route),
    )
/>

【讨论】:

迄今为止最干净的解决方案。正是我需要的。文档表明这将是“故障”,但这不是我的经验。在动画期间,标签栏只是向下滑动并离开视口,然后在您调用 goBack() 时向上滑动。谢谢! 你需要从'@react-navigation/native'导入getFocusedRouteNameFromRoute; 对不起,这是一个愚蠢的问题(React Native 的新手),但为什么首选内联? tabBarVisible 选项不再存在# 由于标签栏现在支持 tabBarStyle 选项,我们删除了 tabBarVisible 选项。您可以通过在选项中指定 tabBarStyle: display: 'none' 来实现相同的行为。 reactnavigation.org/docs/6.x/upgrading-from-5.x/…【参考方案6】:

您无需使用键盘侦听器并更改您的 AndroidManifest.xml 文件,只需添加此 tabBarOptions 道具即可解决此问题:

 <Tab.Navigator

 tabBarOptions=

keyboardHidesTabBar: true,

 >

 </Tab.Navigator>

【讨论】:

【参考方案7】:

Tabbarvisible 属性对我不起作用,我做了一个小变通方法。 它包括 ReactContext + Hoc。

    我们需要做的第一件事是创建一个包含两个字段的反应上下文 可见和设置可见

export const TabBarVisibilityContext = React.createContext(
  visible: false,
  setVisible: () => 
  ,
);
2) 然后我们将创建一个包含选项卡导航器组件的 hoc。

export const TabBarHidable = (Component) => (props) => 
  const [visible, setVisible] = useState(true);
  return (
    <TabBarVisibilityContext.Provider value= visible, setVisible >
      <Component ...props />
    </TabBarVisibilityContext.Provider>
  );
;
    为选项卡导航器组件应用 hoc 并从上下文中提取可见属性。

const  visible, setVisible  = useContext(TabBarVisibilityContext);

    在选项卡导航器选项中更新属性 tabBarOptions = 风格: 变换:!可见 ? [规模:0]:[],

    使用 setVisible 从上下文中隐藏标签栏。

 const  setVisible  = useContext(TabBarVisibilityContext);

useEffect(() => 
 setVisible(false);
  return () => setVisible(true);
, [])

希望它能帮助某人节省他/她的时间。对于给定的问题,我还没有找到合适且简洁的解决方案。

【讨论】:

【参考方案8】:

我正在使用打字稿,我也遇到了这样的问题。由于 tabBarVisible 选项不再可用,我改用 tabBarStyle 并将显示属性设置为“无”。

假设我有两个屏幕,主屏幕是选项卡式屏幕,另一个屏幕说侧屏是堆叠式屏幕,我想在其中隐藏标签栏,然后我在堆叠式屏幕导航器组件中执行此操作:

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

我有一个自定义按钮定义为:

<Button title=btnTitle onPress=onPressHandler/>

在主屏幕上,我有一个按钮,它导航到侧屏幕并通过将自定义 onPressedHandler 属性定义为自定义按钮来隐藏选项卡:

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

然后我有一个按钮传递到下一个屏幕(侧屏幕),标签栏将在返回主屏幕时显示。我将自定义按钮的自定义道具 onPressedHandler 设置为

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

【讨论】:

以上是关于反应导航5从堆栈导航器中隐藏标签栏的主要内容,如果未能解决你的问题,请参考以下文章

从堆栈释放视图,带有导航控制器的标签栏

从底部栏处理返回导航反应原生

每次选择标签栏项目时如何重置导航堆栈?

如何隐藏特定屏幕上的顶部标签栏?

如何在本机反应中隐藏特定屏幕上的底部导航栏?

可以在标签栏控制器中隐藏导航栏吗?