“更多”覆盖额外的标签在React导航和底部标签-如何?

lnvxswe2  于 2023-10-22  发布在  React
关注(0)|答案(1)|浏览(159)

在我的应用程序中,我使用react-navigation(v5),并在所有主屏幕上使用BottomTabNavigator
我想确保额外的选项卡(超过5个)被隐藏在一个特殊的“更多”选项卡中,该选项卡将打开一个屏幕列表-从那里,它们应该像普通选项卡一样工作,但只有当“更多”选项卡被激活时才会显示。
这是设计师的设想。(忽略红色计数器)
如何使用react-navigation的选项实现这样的功能,而不需要太多的自定义代码或外部依赖?

ftf50wuq

ftf50wuq1#

我遇到了你的问题,因为我面临着同样的问题。我已经设法做了,但我对我的解决办法不满意。既然已经有一段时间没有其他答案了,你有没有找到更好的解决办法?
我的方法是防止在点击标签栏时打开屏幕,而是打开一个菜单。以下是您可以实现这一点的方法:

function GeneralTabs() {
  const [isMenuVisible, setIsMenuVisible] = useState(false)
  return(
  <>
    <Tab.Navigator
    screenOptions={{ headerShown: false }}
    initialRouteName="Myheder"
    >
    //other Tab.Screens
    <Tab.Screen
      name="More"
      component={() => null}
      listeners={() => ({
        tabPress: (e) => {
          e.preventDefault()
          setIsMenuVisible(true)
        }
      })}
      options={{
        tabBarIcon: ({ color, size }) => {
          return(
            <MaterialIcons name="more-horiz" color={color} size={size}/>
          )
        }
      }}
    />

    <Menu
      visible={isMenuVisible}
      onDismiss={() => setIsMenuVisible(false)}
      anchor={{x: 0, y: 0}}
    >
      <Menu.Item leadingIcon="account-circle" onPress={() => {/* navigation to my account */}} title="My account" />
      <Menu.Item leadingIcon="tune" onPress={() => {/* navigation to settings */}} title="Settings" />
    </Menu>
  </>
)

更新:

我想更好的解决方案是创建自定义导航器。主要区别是通过将tabBar属性传递给Tab.Navigator来重新定义底部导航器的外观和行为。
下面是我喜欢的例子,然后以前的解决方案:

const routeMapping: Record<
  string,
  { icon: string; component: React.ComponentType<any> }
> = {
  Meetings: {
    icon: 'voice-chat',
    component: MeetingsNavigator,
  },
  Chat: {
    icon: 'chat',
    component: Chat,
  },
  More: {
    icon: 'more-horiz',
    component: MoreNullComponent,
  },
}

function GeneralTabs() {
  return (
    <Tab.Navigator
      initialRouteName="Meetings"
      screenOptions={({ route }) => ({
        tabBarLabelPosition: 'below-icon',
        headerShown: false,
        tabBarIcon: ({ color, size }) => {
          return (
            <MaterialIcons
              name={routeMapping[route.name].icon}
              color={color}
              size={size}
            />
          )
        },
      })}
      tabBar={(props) => <TabBar {...props} />}
    >
      {Object.keys(routeMapping).map((routeName) => (
        <Tab.Screen
          key={routeName}
          name={routeName}
          component={routeMapping[routeName].component}
        />
      ))}
    </Tab.Navigator>
  )
}

您的TabBar组件可能看起来像:

import { type BottomTabBarProps } from '@react-navigation/bottom-tabs'
    import React, { useState } from 'react'
    import { View, StyleSheet, TouchableOpacity } from 'react-native'
    import { Menu } from 'react-native-paper'
    import BottomBarButton from '../components/BottomBarButton'

    export default function TabBar({ state, descriptors, navigation }: BottomTabBarProps) {
    return (
        <View style={styles.mainContainer}>
        {state.routes.map((route: any, index: number) => {
            const { options } = descriptors[route.key]
            const isFocused = state.index === index
            const iconNode = options.tabBarIcon?.({
            focused: isFocused,
            color: isFocused ? 'blue' : 'gray',
            size: 20,
            })

            if (route.name == 'More') {
            const [isVisible, setIsVisible] = useState(false)
            return (
                <View key={index}>
                    <TouchableOpacity
                        key={index}
                        onPress={() => {
                            setIsVisible(true)
                        }}
                    >
                    <Menu
                        visible={isVisible}
                        onDismiss={() => {
                        setIsVisible(false)
                        }}
                        anchor={
                        <View style={styles.iconContainer}>
                            <BottomBarButton icon={iconNode} label={route.name} />
                        </View>
                        }
                    >
                        <Menu.Item leadingIcon="account-circle" title="My account"/>
                        <Menu.Item leadingIcon="logout" onPress={() => {}} title="Logout" />
                    </Menu>
                    </TouchableOpacity>
                </View>
            )
            }

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

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

            return (
            <View key={index}>
                <TouchableOpacity onPress={onPress}>
                <View style={styles.iconContainer}>
                    <BottomBarButton icon={iconNode} label={route.name}/>
                </View>
                </TouchableOpacity>
            </View>
            )
        })}
        </View>
    )
    }

    const styles = StyleSheet.create({
    mainContainer: {
        flexDirection: 'row',
        justifyContent: 'space-around',
        alignItems: 'center',
        height: 50,
        borderTopWidth: 1,
        borderTopColor: 'lightgray',
    },

    iconContainer: {
        alignItems: 'center',
        justifyContent: 'center',
    },
    })

结果在这里:

相关问题