【问题标题】:React Navigation 5 Hide Drawer ItemReact Navigation 5 隐藏抽屉项目
【发布时间】:2020-06-09 05:44:59
【问题描述】:

我试图隐藏在抽屉导航器中按下我的一条路线的能力,因为它是另一个导航器和应用程序中的默认位置。我希望抽屉仅用于导航到不适合其他地方的用户流的无关路线。在 React Navigation 5 之前,我可以通过简单地设置 drawerLabel: () => null 来实现这一点。但是现在有了这些更改,我无法弄清楚如何以相同的方式隐藏它。

以下是我当前的导航器代码:

const DrawerNavigator = () => {
    const dispatch = useDispatch();
    return (
    <MainDrawerNavigator.Navigator 
        drawerContent={props => customDrawerContent(props, dispatch)}
        drawerStyle={drawerStyle}
    >
        <MainDrawerNavigator.Screen 
            name="DrawerNav"
            component={MainTabNavigator}
            options={{
                drawerLabel: () => null,
                title: null,
                drawerIcon: () => null
            }}
        />

        <MainDrawerNavigator.Screen
            name="FAQNav"
            component={FAQStackNavigator}
            options={
                { 
                    drawerLabel: "FAQ", 
                    drawerIcon: ({tintColor}) => <EvilIcons name={'question'} size={30} color={tintColor} />
                }
            }
        />
    </MainDrawerNavigator.Navigator>
    )
}

const customDrawerContent = (props, dispatch) => {
    console.log(props.descriptors)
    return (
        <View style={{flex: 1}}>
            <View style={{height: '90%'}}>

                <DrawerContentScrollView {...props}>
                        <View style={styles.logoContainer}>
                            <Image 
                                style={styles.image} 
                                fadeDuration={0} 
                                resizeMode={'contain'} 
                                source={require('../assets/images/spikeball-logo-horizontal.png')} 
                            />
                        </View>

                        <TouchableOpacity style={styles.contactUsContainer} onPress={() => { Linking.openURL('https://spikeball.com/')}}>
                            <AntDesign style={styles.iconStyle} name={'shoppingcart'} size={25} color={'black'} />

                            <Text style={styles.drawerText}>Shop</Text>                    
                        </TouchableOpacity>

                        <TouchableOpacity style={styles.contactUsContainer} onPress={() => { Linking.openURL('https://support.spikeball.com/')}}>
                            <AntDesign style={styles.iconStyle} name={'contacts'} size={25} color={'black'} />

                            <Text style={styles.drawerText}>Contact Us</Text>                    
                        </TouchableOpacity>

                        <DrawerItemList 
                            {...props}
                        />

                </DrawerContentScrollView>
            </View>

            <TouchableOpacity 
                style={styles.logoutContainer} 
                onPress={() => { 
                    dispatch(authActions.logout());
                }}>
                    <Text style={styles.logoutText}>SIGN OUT</Text>                    
            </TouchableOpacity>
        </View>
    )
}

链接到显示不需要的输出的图像。基本上我希望蓝色焦点和整个导航项目专门从导航栏隐藏。 UNDESIRED Output

【问题讨论】:

    标签: react-native react-navigation react-navigation-drawer react-navigation-v5


    【解决方案1】:

    最好的解决方案是在将 props 传递给 DrawerItemList 之前对其进行过滤。这只适用于反应导航 5

    //custom drawer content
    export default props => {
    const { state, ...rest } = props;
    const newState = { ...state}  //copy from state before applying any filter. do not change original state
    newState.routes = newState.routes.filter(item => item.name !== 'Login') //replace "Login' with your route name
    
    return (
         <DrawerContentScrollView {...props}>
             <DrawerItemList state={newState} {...rest} />
        </DrawerContentScrollView>
    )
    

    }

    【讨论】:

    • 如何隐藏多个抽屉项目?
    • 嘿 @MayankBudhiraja 像这样更新过滤器: newState.routes = newState.routes.filter(item => !['RouteOne', 'Login', 'Signup' ].includes(item.name ));
    • 在我的情况下不起作用。做了完全一样的事情。问另一个问题。
    • 按预期工作!
    • 工作但有时无法导航到另一个屏幕
    【解决方案2】:

    解决了以下问题

    import React from 'react';
    import { SafeAreaView, View, Text, StyleSheet, Image, Linking } from 'react-native';
    import { EvilIcons, AntDesign } from '@expo/vector-icons';
    import { useDispatch } from 'react-redux';
    import { createDrawerNavigator, DrawerContentScrollView, DrawerItemList, DrawerItem } from '@react-navigation/drawer';
    
    import MainTabNavigator from './MainTabNavigator';
    import FAQStackNavigator from './FAQStackNavigator';
    import { TouchableOpacity } from 'react-native-gesture-handler';
    import * as authActions from '../store/actions/auth';
    import { moderateScale } from '../utils/fontScale';
    
    const MainDrawerNavigator = createDrawerNavigator();
    
    const DrawerNavigator = () => {
        const dispatch = useDispatch();
        return (
        <MainDrawerNavigator.Navigator 
            drawerContent={props => customDrawerContent(props, dispatch)}
            drawerStyle={drawerStyle}
        >
            <MainDrawerNavigator.Screen 
                name="DrawerNav"
                component={MainTabNavigator}
                options={{
                    drawerLabel: () => null,
                    title: null,
                    drawerIcon: () => null
                }}
            />
    
            <MainDrawerNavigator.Screen
                name="FAQNav"
                component={FAQStackNavigator}
                options={
                    { 
                        drawerLabel: "FAQ", 
                        drawerIcon: ({tintColor}) => <EvilIcons name={'question'} size={30} color={tintColor} />
                    }
                }
            />
        </MainDrawerNavigator.Navigator>
        )
    }
    
    const customDrawerContent = (props, dispatch) => {
        return (
            <View style={{flex: 1}}>
                <View style={{height: '90%'}}>
    
                    <DrawerContentScrollView {...props}>
                            <View style={styles.logoContainer}>
                                <Image 
                                    style={styles.image} 
                                    fadeDuration={0} 
                                    resizeMode={'contain'} 
                                    source={require('...')} 
                                />
                            </View>
    
                            <TouchableOpacity style={styles.contactUsContainer} onPress={() => { Linking.openURL('...')}}>
                                <AntDesign style={styles.iconStyle} name={'shoppingcart'} size={25} color={'black'} />
    
                                <Text style={styles.drawerText}>Shop</Text>                    
                            </TouchableOpacity>
    
                            <TouchableOpacity style={styles.contactUsContainer} onPress={() => { Linking.openURL('...')}}>
                                <AntDesign style={styles.iconStyle} name={'contacts'} size={25} color={'black'} />
    
                                <Text style={styles.drawerText}>Contact Us</Text>                    
                            </TouchableOpacity>
    
                            {/* Tried just disabling using DrawerItemList but wasn't working so made
                            complete custom drawer component and navigate properly using props.navigation.navigate */}
                            {/* <DrawerItemList 
                                {...props}
                            /> */}
    
                            <TouchableOpacity 
                                style={styles.contactUsContainer} 
                                onPress={() => { console.log(props.navigation.navigate('FAQNav'))}}
                            >
                                <EvilIcons name={'question'} size={30} color={'black'} />
                                <Text style={styles.drawerText}>FAQ</Text>                    
                            </TouchableOpacity>
                    </DrawerContentScrollView>
                </View>
    
                <TouchableOpacity 
                    style={styles.logoutContainer} 
                    onPress={() => { 
                        dispatch(authActions.logout());
                    }}>
                        <Text style={styles.logoutText}>SIGN OUT</Text>                    
                </TouchableOpacity>
            </View>
        )
    }
    
    const drawerStyle = {
        activeTintColor: 'black',
        inactiveTintColor: 'black',
        labelStyle: {
            fontFamily: 'montserrat',
            marginVertical: 16,
            marginHorizontal: 0,
        },
        iconContainerStyle: {
            justifyContent: 'center',
            alignItems: 'center',
        },
        itemStyle: {
    
        }
    }
    
    const styles = StyleSheet.create({
        safeArea: {
            flex: 1,
            paddingTop: Platform.OS === 'android' ? 25 : 0
        },
        container: {
            flex: 1,  
        },
        logoContainer: {
            width: '100%',
            height: moderateScale(50),
            alignItems: 'center',
            justifyContent: 'center',
            marginBottom: 5,
            padding: 5,
        },
        image: {
            resizeMode: 'contain',
            width: '80%',
            height: '100%',
        },
        contactUsContainer: {
            flexDirection: 'row',
            width: '100%',
            height: 50,
            alignItems: 'center',
            paddingLeft: 15
        },
        logoutContainer: {
            flexDirection: 'row',
            width: '100%',
            height: 50,
            alignItems: 'flex-end',
            justifyContent: 'center',
        },
        drawerText: {
            fontFamily: 'montserrat',
            marginLeft: 16,
        },
        logoutText: {
            fontFamily: 'montserrat',
            color: '#b23b3b'
        }
    });
    
    export default DrawerNavigator;
    

    【讨论】:

    • @Matheus 在我的应用程序中,它们根本不可点击。没有可点击的空间。如果我检查抽屉中的实际元素,它们是不可见或不可点击的。
    • 抽屉项目已隐藏,但我仍然可以在该位置留出一些空间。你知道怎么去掉吗?
    • @harshitraghav 我通过在customDrawerContent 上方创建自己的抽屉内容来实现它。如果您注意到 DrawerItemList 被注释掉了,然后我会使用自己的项目组件自己处理导航。
    • 我必须道歉。我没有检查你绘制每个项目的部分,它确实有效。更改您的答案中的一些字母,以便我可以更改我的投票。感谢您的回答。
    • @Matheus 不用担心!很高兴它有帮助!
    【解决方案3】:

    浏览了 React Navigation 源代码后,我认为最好的选择是在要隐藏的抽屉屏幕上添加一个drawerItemStyle 选项。只需将高度设置为 0。

    例如

    <Drawer.Screen
      name="Home"
      component={MainStackScreen}
      options={{
        drawerItemStyle: { height: 0 }
      }}
    />
    

    它似乎工作得很好。

    我正在使用 React Navigation 6,但这可能也适用于 v5。

    【讨论】:

    • 这导致我尝试使用 display: "none" 而不是 height: 0 并且效果很好!它还删除了内置的填充/边距
    • 简单有效;-)
    【解决方案4】:

    对我来说,您最好创建一个嵌套导航器,其中包含 https://reactnavigation.org/docs/nesting-navigators/#navigator-specific-methods-are-available-in-the-navigators-nested-inside 中记录的堆栈和抽屉屏幕,而不是隐藏抽屉项目。

    【讨论】:

    • 这也是一个不好的解决方案,我试过了。这样做时,您所做的就是替换一堆您想隐藏在抽屉中的屏幕,以替换“一个”屏幕,例如堆栈导航器。除了链接文档之外,也许您可​​以提供一个更好的示例,因为这些文档很糟糕。谢谢
    • 补充@Matheus 所写的内容,当我尝试这种方式时,我看到iOS 上出现了一些奇怪的闪烁,当使用抽屉作为顶部导航器进行测试时,它非常流畅。
    【解决方案5】:

    React Navigation 5 的解决方案

    我最终使用了以下代码 -

    drawerContent={props => customDrawerContent(props, dispatch)}
    

    customDrawerContent 的代码 -

    {state.routes.map((route, i) => {
              if(route.name === 'App') return;
              const focused = i === state.index;
              const { title, drawerLabel, drawerIcon } = descriptors[route.key].options;
    
              return (
                <DrawerItem
                  key={route.key}
                  label={
                    drawerLabel !== undefined
                      ? drawerLabel
                      : title !== undefined
                      ? title
                      : route.name
                  }
                  icon={drawerIcon}
                  focused={focused}
                  activeTintColor={activeTintColor}
                  inactiveTintColor={inactiveTintColor}
                  activeBackgroundColor={activeBackgroundColor}
                  inactiveBackgroundColor={inactiveBackgroundColor}
                  labelStyle={labelStyle}
                  style={itemStyle}
                  to={buildLink(route.name, route.params)}
                  onPress={() => {
                    navigation.dispatch({
                      ...(focused
                        ? DrawerActions.closeDrawer()
                        : CommonActions.navigate(route.name)),
                      target: state.key,
                    });
                  }}
                />
              );
            })}
    

    完整的代码可以在这里找到-

    https://gist.github.com/yashkumarsharma/a56f4fe1517ee8ce07c153d2d2795f6f

    【讨论】:

      【解决方案6】:

      在我踩到 Github 上的 How to hide DrawerView.Item in DrawerNavigator contentComponent #795 之前,上述解决方案均不适合我。

      其他人 cmets 允许我为 react-native v5 提出一个动态且可行的解决方案。

      const CustomDrawer = props => {
        const {state, descriptors, navigation} = props;
        const buildLink = useLinkBuilder();
      
        return (
          <DrawerContentScrollView {...props}>
            {state.routes.map((route, i) => {
              const isHidden = descriptors[route.key].options?.hidden; // <--- Added this line
              if (isHidden === true) return null; // <--- Added this line
      
              const focused = i === state.index;
              const {
                title,
                drawerLabel,
                drawerIcon,
                drawerActiveTintColor,
                drawerInactiveTintColor,
                drawerActiveBackgroundColor,
                drawerInactiveBackgroundColor,
                drawerLabelStyle,
                drawerItemStyle,
              } = descriptors[route.key].options;
      
              return (
                <DrawerItem
                  key={route.key}
                  label={
                    drawerLabel !== undefined
                      ? drawerLabel
                      : title !== undefined
                      ? title
                      : route.name
                  }
                  icon={drawerIcon}
                  focused={focused}
                  activeTintColor={drawerActiveTintColor}
                  inactiveTintColor={drawerInactiveTintColor}
                  activeBackgroundColor={drawerActiveBackgroundColor}
                  inactiveBackgroundColor={drawerInactiveBackgroundColor}
                  labelStyle={drawerLabelStyle}
                  style={drawerItemStyle}
                  to={buildLink(route.name, route.params)}
                  onPress={() => {
                    navigation.dispatch({
                      ...(focused
                        ? DrawerActions.closeDrawer()
                        : CommonActions.navigate(route.name)),
                      target: state.key,
                    });
                  }}
                />
              );
            })}
          </DrawerContentScrollView>
        );
      };
      
      export default CustomDrawer;
      

      那么你所要做的就是在 Drawer.Navigator 中使用 CustomDrawer 并将隐藏选项传递给 Drawer.Screen,如下所示:

      <Drawer.Navigator
                    initialRouteName={ROUTES.SIGN_IN}
                    drawerPosition="right"
                    drawerContent={props => <CustomDrawer {...props} />}>
                    <Drawer.Screen
                      name={ROUTES.SIGN_IN}
                      component={SignInContainer}
                      options={{headerShown: false, hidden: true}}
                    />
                    <Drawer.Screen
                      name={ROUTES.DASHBOARD}
                      component={withHeader(DashboardContainer)}
                      options={{headerLeft: false}}
                    />
      </Drawer.Navigator>
      

      【讨论】:

        【解决方案7】:

        @Lenin Sheikh 解决方案有效,但正如 cmets 中强调的那样,它引入了另一个问题,即无法单击抽屉菜单中的某些组件。我通过两个步骤解决了这个问题(显然是在应用@Lenin Sheikh 解决方案之后)。

        1. 将隐藏的项目移到列表底部

        2. 选择一个默认组件,尤其是当它是隐藏组件之一时

          <Drawer.Navigator
                    initialRouteName='Home'// Specify the default component
                 drawerContent={
                   (props) => (
                     <DrawerList {...props} />)
                 }>
          
                 <Drawer.Screen name="Component 1"
                                component={Component1}
                                options={{ title: "Component one", headerShown: 
             false }} />
          
           <Drawer.Screen name="Component 2"
                            component={Component2}
                            options={{ title: "Component 2", headerShown: false 
          }} />
          
          
          
           <Drawer.Screen name="Logout"
                        component={LogoutPage}
                        options={{ title: "Logout", headerShown: true }} />
          
          <Drawer.Screen name="Home" component={HomePage}
                        options={{
                          title: "",
                          headerShown: false,
          
                        }} />//This is the hidden component
          
          </Drawer.Navigator>
          

        【讨论】:

          【解决方案8】:

          我刚刚找到了解决类似问题的方法。长话短说,我使用 Stack、Tabs 和 Drawer(用于汉堡菜单)。我设法合并了所有导航,但抽屉显示了我不想要的主页按钮。

          我找到的解决方案在这里:

          我也遇到了问题,第一个抽屉菜单选项被突出显示并且不可点击。为此,我只需将隐藏的菜单屏幕移动到抽屉导航的底部。 :) 我知道这不是最漂亮的解决方案,但我想我明白了。我希望它会帮助某人。这是我的代码:

          function DrawerNavigator() {
            return (
              <NavigationContainer>
                <Drawer.Navigator
                  initialRouteName="Home"
                  drawerContent={props => {
                    const filteredProps = {
                      ...props,
                      state: {
                        ...props.state,
                        routeNames: props.state.routeNames.filter(routeName => {
                          routeName !== 'Home';
                        }),
                        routes: props.state.routes.filter(route => route.name !== 'Home'),
                      },
                    };
                    return (
                      <DrawerContentScrollView {...filteredProps}>
                        <DrawerItemList {...filteredProps} />
                      </DrawerContentScrollView>
                    );
                  }}>
                  <Drawer.Screen name="Notifications" component={ProfileScreen} />
                  <Drawer.Screen name="Notifications2" component={ProfileScreen} />
                  <Drawer.Screen name="Home" component={StackNavigator} />
                </Drawer.Navigator>
              </NavigationContainer>
            );
          }
          

          附言所有屏幕都是假的,所以忽略它没有意义:)

          当我睡个好觉并重构它时,我可以并且会分享我的整个导航,但不要犹豫,询问您是否需要更多代码。干杯!

          【讨论】:

            猜你喜欢
            • 2020-09-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-04-07
            • 2021-01-12
            • 1970-01-01
            • 1970-01-01
            • 2022-06-30
            相关资源
            最近更新 更多