10
votes

React navigation 5 Masquer la barre d'onglets du navigateur de pile

Je voulais savoir comment masquer la barre d'onglets inférieure d'un écran spécifique dans mon navigateur de pile qui est imbriquée dans une barre d'onglets inférieure de matériau

Ceci est mon code pour mon navigateur de pile

{
  "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
}

Ceci est mon code pour mon navigateur d'onglet inférieur matériel

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

J'utilise actuellement Expo pour construire mon projet.

Mes dépendances (package.json)

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


1 commentaires

Pour votre prochaine question, vous souhaiterez peut-être marquer votre question avec React-navigation afin que davantage de personnes puissent la voir.


5 Réponses :


9
votes

Vous devriez essayer de réorganiser votre calque d'écran,

Original

  • Barre d'onglets
    • Étang (pile)
      • PondScreen
      • DetailScreen
    • Stock
    • Autres

Au lieu de cela, essayez de placer une pile supérieure sur

  • TopStack
    • Barre d'onglets
      • PondScreen
      • Stock
      • Autres
    • Détails

Cela devrait pouvoir masquer la barre d'onglets inférieure ou l'en-tête de l'onglet dans chaque écran


3 commentaires

Cela devrait être la réponse acceptée car c'est celle recommandée par la documentation.


Une idée comment faire avec cela avec plusieurs piles? Une autre pile après avoir navigué via l'onglet?


Si vous avez des piles imbriquées, placez-les simplement dans la pile la plus basse. C'est comme ça que ça a fonctionné pour moi. Là, j'ai remplacé le composant d'accueil par le nav TabBar.



37
votes

J'ai eu presque le même problème avec une tabnavigation en tant que parent et stacknavigation en tant qu'enfant et la réorganisation de ma couche d'écran n'était pas une option. J'ai donc cherché une autre solution et à partir des documents, j'ai découvert que l'interface utilisateur de navigation parentale était toujours affichée sur l'enfant. Mais la documentation a également donné un excellent exemple sur la façon de modifier un en-tête parent à partir d'un enfant. J'ai donc pris cet exemple et l'ai implémenté pour la visibilité de la barre d'onglets. C'est ainsi que je l'ai implémenté.

J'ai donc une barre d'onglets de navigation avec Accueil, Contacts et plus, et à l'intérieur de chaque onglet, j'ai une pile. L'écran dans lequel je cache la barre d'onglets se trouve dans CameraView, et cet écran est un écran de pile dans l'onglet Plus.

  • Accueil
  • Contacts
  • Plus
    • Profil
    • CameraView (ici je veux cacher la barre d'onglets)

Tabnavigation:

Comme vous pouvez le voir, j'obtiens la visibilité de la barre d'onglets à partir d'une méthode.

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

Méthode getTabBarVisibility:

C'est là que je vérifie si le nom de la route est CameraView que j'ai défini dans StackNavigation.

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

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

  return true;
}

Et le composant MoreNavigation:

Ceci est ma stacknavigation pour Plus, où vous pouvez voir que le nom d'écran est CameraView.

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


10 commentaires

@BoyPasmo Heureux que je puisse vous aider!


La documentation recommande de ne pas utiliser cette approche car elle provoquera des animations glitchy avec le composant de pied de page. Je recommanderais de ne pas utiliser cette approche et de réorganiser vos pages comme le suggère la documentation.


@EricWiener la documentation a été récemment mise à jour, j'ai donné cette réponse avant que la documentation ne soit mise à jour. Nous n'avons rencontré aucun problème dans notre application. Pour cela, nous nous en tenons à cette solution et ne réorganiserons pas nos pages, alors qu'il est étrange d'avoir une pile supplémentaire que vous n'utilisez pas, uniquement pour cacher un bottombar. Au fait, ils suggèrent cette approche si vous souhaitez définir l'en-tête différemment ....


@Emmie l'a compris. Merci de me le faire savoir. Votre réponse fait définitivement le travail, mais pour moi, cela faisait disparaître la barre d'onglets trop tôt avant de naviguer vers une nouvelle page.


@EricWiener Bon à savoir, lorsque nous avons des problèmes de pépin, nous nous pencherons sur cela.


@EricWiener merci de son travail mais il montre un espace blanc en bas lorsque je cache l'onglet du bas dans nextscreen. Quelqu'un a quelquonque idée.


@pragnesh J'ai fini par avoir le même problème lors de l'utilisation d'un onglet inférieur avec une vue Accessoire clavier. Je cache la barre d'onglets sur l'écran qui posait problème et j'affiche un composant de barre d'onglets identique en tant qu'enfant de cet écran


Cela a fonctionné pour moi lors de la transition vers une WebView qui a pris en charge la vue entière, mais lorsque l'utilisateur glisse pour revenir en arrière, cela a un peu changé l'animation: /


"tabBarVisible" n'est pas disponible dans createMaterialBottomTabNavigator, donc cela ne fonctionne pas!


@AdamRi n'est pas disponible pour createMaterialBottomTabNavigator spécifique. Cela fonctionne donc pour l'utilisateur qui a posé la question, mais cela ne fonctionne pas pour le fond de matériau spécifique.



6
votes

L'astuce consiste à ajouter TabsStack, OtherStack ou SomeOtherScreen dans votre

<Stack.Navigator /> via un <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>
  );
}

c'est documenté ici


3 commentaires

Merci Luke. Bonne réponse avec un exemple de code dedans et ça marche


J'avais l'habitude d'avoir ceci sur Navigation4.x mais dans 5, tout est comme neuf, donc cela me manque. Ça marche


Merci, c'est la meilleure solution, vous pouvez afficher uniquement l'en-tête TabsStack et masquer le "Stack.Screen" en utilisant options = {{headerShown: false}} comme ceci: <Stack.Screen name = "TabsStack" component = {TabsStack} options = {{headerShown: false}} />



1
votes

Ajoutez cette fonction pour masquer la barre inférieure dans MyTabBar

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

MyTabBar

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

ajouter la visibilité de la barre inférieure dans la pile d'écran

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

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

      return true;
    };

Ajouter des options dans les navigateurs des onglets principaux

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

Ajouter un écran de profil dans More Stack

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


1 commentaires

Cela fonctionne aussi. Merci



1
votes

La réponse acceptée est excellente, mais vous voudrez peut-être le faire en ligne et utiliser getFocusedRouteNameFromRoute pour être sûr. Ce code fait la même chose que la réponse acceptée:

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

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

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


1 commentaires

J'ai essayé cela et cela fonctionne. C'est vraiment une alternative en ligne