跳到主要内容
版本: 7.x

底部标签导航器

屏幕底部的简单标签栏,可让您在不同路由之间切换。路由是延迟初始化的 -- 它们的屏幕组件在首次聚焦之前不会被挂载。

安装

要使用此导航器,请确保您已安装 @react-navigation/native 及其依赖项(请按照本指南),然后安装 @react-navigation/bottom-tabs

npm install @react-navigation/bottom-tabs

用法

要使用此导航器,请从 @react-navigation/bottom-tabs 导入它

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

const MyTabs = createBottomTabNavigator({
screens: {
Home: HomeScreen,
Profile: ProfileScreen,
},
});
Snack 上尝试

API 定义

属性

除了所有导航器共享的通用属性外,底部标签导航器还接受以下附加属性

backBehavior

这控制了在导航器中调用 goBack 时会发生什么。 这包括按下设备的后退按钮或 Android 上的后退手势。

它支持以下值

  • firstRoute - 返回到导航器中定义的第一个屏幕(默认)
  • initialRoute - 返回到在 initialRouteName 属性中传递的初始屏幕;如果未传递,则默认为第一个屏幕。
  • order - 返回到聚焦屏幕之前定义的屏幕
  • history - 返回到导航器中上次访问的屏幕;如果同一屏幕被多次访问,则较旧的条目将从历史记录中删除。
  • none - 不处理后退按钮

detachInactiveScreens

布尔值,用于指示是否应将非活动屏幕从视图层次结构中分离出来以节省内存。这实现了与 react-native-screens 的集成。默认为 true

tabBar

返回一个 React 元素以显示为标签栏的函数。

该函数接收一个对象作为参数,其中包含以下属性:

  • state - 标签导航器的状态对象。
  • descriptors - 描述符对象,其中包含标签导航器的选项。
  • navigation - 标签导航器的导航对象。

state.routes 数组包含导航器中定义的所有路由。可以使用 descriptors[route.key].options 访问每个路由的选项。

示例

import { View, Platform } from 'react-native';
import { useLinkBuilder, useTheme } from '@react-navigation/native';
import { Text, PlatformPressable } from '@react-navigation/elements';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

function MyTabBar({ state, descriptors, navigation }) {
const { colors } = useTheme();
const { buildHref } = useLinkBuilder();

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, route.params);
}
};

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

return (
<PlatformPressable
href={buildHref(route.name, route.params)}
accessibilityState={isFocused ? { selected: true } : {}}
accessibilityLabel={options.tabBarAccessibilityLabel}
testID={options.tabBarButtonTestID}
onPress={onPress}
onLongPress={onLongPress}
style={{ flex: 1 }}
>
<Text style={{ color: isFocused ? colors.primary : colors.text }}>
{label}
</Text>
</PlatformPressable>
);
})}
</View>
);
}

const MyTabs = createBottomTabNavigator({
tabBar: (props) => <MyTabBar {...props} />,
screens: {
Home: HomeScreen,
Profile: ProfileScreen,
},
});
Snack 上尝试

此示例将渲染一个带有标签的基本标签栏。

请注意,您不能tabBar 内部使用 useNavigation Hook,因为 useNavigation 仅在屏幕内部可用。 您可以为您的 tabBar 获取一个 navigation 属性,您可以改用它。

function MyTabBar({ navigation }) {
return (
<Button
onPress={() => {
// Navigate using the `navigation` prop that you received
navigation.navigate('SomeScreen');
}}
>
Go somewhere
</Button>
);
}

选项

以下选项可用于配置导航器中的屏幕。 这些可以在 Tab.navigatorscreenOptions 属性或 Tab.Screenoptions 属性下指定。

title

通用标题,可以用作 headerTitletabBarLabel 的后备。

tabBarLabel

标签栏中显示的选项卡的标题字符串,或给定 { focused: boolean, color: string } 返回 React.Node 以在标签栏中显示的函数。 未定义时,使用场景 title。 要隐藏,请参阅 tabBarShowLabel

tabBarShowLabel

选项卡标签是否应可见。 默认为 true

tabBarLabelPosition

标签是显示在图标下方还是图标旁边。

默认情况下,位置会根据设备宽度自动选择。

  • below-icon: 标签显示在图标下方(iPhone 的典型情况)

    Tab bar label position - below
  • beside-icon 标签显示在图标旁边(iPad 的典型情况)

    Tab bar label position - beside

tabBarLabelStyle

选项卡标签的样式对象。

Tab bar label style

示例

    tabBarLabelStyle: {
fontSize: 16,
fontFamily: 'Georgia',
fontWeight: 300,
},

tabBarIcon

给定 { focused: boolean, color: string, size: number } 返回 React.Node 以在标签栏中显示的函数。

tabBarIconStyle

选项卡图标的样式对象。

tabBarBadge

要在选项卡图标上的徽章中显示的文本。 接受 stringnumber

Tab bar badge

tabBarBadgeStyle

选项卡图标上徽章的样式。 您可以在此处指定背景颜色或文本颜色。

Tab bar badge style

示例

    tabBarBadgeStyle: {
color: 'black',
backgroundColor: 'yellow',
},

tabBarAccessibilityLabel

选项卡按钮的辅助功能标签。 当用户点击选项卡时,屏幕阅读器会读取此标签。 如果您没有选项卡的标签,建议设置此标签。

tabBarButton

返回一个 React 元素以渲染为标签栏按钮的函数。 它包装了图标和标签。 默认情况下渲染 Pressable

您可以在此处指定自定义实现。

tabBarButton: (props) => <TouchableOpacity {...props} />;

tabBarButtonTestID

在测试中定位此选项卡按钮的 ID。

tabBarActiveTintColor

活动选项卡中图标和标签的颜色。

Tab bar active tint color

tabBarInactiveTintColor

非活动选项卡中图标和标签的颜色。

Tab bar inactive tint color

tabBarActiveBackgroundColor

活动选项卡的背景颜色。

tabBarInactiveBackgroundColor

非活动选项卡的背景颜色。

tabBarHideOnKeyboard

当键盘打开时,标签栏是否隐藏。 默认为 false

tabBarItemStyle

选项卡项目容器的样式对象。

tabBarStyle

标签栏的样式对象。 您可以在此处配置背景颜色等样式。

要在标签栏下方显示您的屏幕,您可以将 position 样式设置为 absolute

<Tab.Navigator
screenOptions={{
tabBarStyle: { position: 'absolute' },
}}
>

如果您有一个绝对定位的标签栏,您可能还需要为您的内容添加底部边距。 React Navigation 不会自动执行此操作。 有关更多详细信息,请参阅 useBottomTabBarHeight

tabBarBackground

返回一个 React 元素以用作标签栏背景的函数。 您可以渲染图像、渐变、模糊视图等。

import { BlurView } from 'expo-blur';

// ...

<Tab.Navigator
screenOptions={{
tabBarStyle: { position: 'absolute' },
tabBarBackground: () => (
<BlurView tint="light" intensity={100} style={StyleSheet.absoluteFill} />
),
}}
>

使用 BlurView 时,请确保也在 tabBarStyle 中设置 position: 'absolute'。 您还需要使用 useBottomTabBarHeight 为您的内容添加底部内边距。

Tab bar background

tabBarPosition

标签栏的位置。 可用值包括:

  • bottom (默认)
  • top
  • left
  • right

当标签栏位于 leftright 时,它被样式化为侧边栏。 当您想在较大屏幕上显示侧边栏,在较小屏幕上显示底部标签栏时,这可能很有用。

const Tabs = createBottomTabNavigator({
screenOptions: {
tabBarPosition: isLargeScreen ? 'left' : 'bottom',
},

// ...
});
Sidebar

您还可以通过将标签放在图标下方来渲染紧凑型侧边栏。 这仅在 tabBarVariant 设置为 material 时才受支持。

const Tabs = createBottomTabNavigator({
screenOptions: {
tabBarPosition: isLargeScreen ? 'left' ? 'bottom',
tabBarVariant: isLargeScreen ? 'material' : 'uikit',
tabBarLabelPosition: 'below-icon',
},

// ...
});

Compact sidebar

tabBarVariant

标签栏的变体。 可用值包括:

  • uikit (默认) - 标签栏将根据 iOS UIKit 指南进行样式设置。
  • material - 标签栏将根据 Material Design 指南进行样式设置。

material 变体目前仅在 tabBarPosition 设置为 leftright 时受支持。

Material sidebar

lazy

此屏幕是否应仅在首次访问后才渲染。 默认为 true。 如果您想在导航器的初始渲染时渲染屏幕,请将其设置为 false

freezeOnBlur

布尔值,指示是否阻止非活动屏幕重新渲染。 默认为 false。 当从 react-native-screens 包中的 enableFreeze() 在应用程序顶部运行时,默认为 true

仅在 iOS 和 Android 上受支持。

popToTopOnBlur

布尔值,指示在离开此选项卡时,是否应将任何嵌套堆栈弹出到堆栈顶部。 默认为 false

它仅在标签导航器下嵌套堆栈导航器(例如堆栈导航器或原生堆栈导航器)时才有效。

sceneStyle

包装屏幕内容的组件的样式对象。

您可以在此处找到标题相关选项的列表。 这些选项可以在 Tab.navigatorscreenOptions 属性或 Tab.Screenoptions 属性下指定。 您不必直接使用 @react-navigation/elements 来使用这些选项,它们只是在该页面中记录。

除此之外,底部标签还支持以下选项:

要使用的自定义标题栏,而不是默认标题栏。

这接受一个返回 React 元素以显示为标题的函数。 该函数接收一个对象作为参数,其中包含以下属性:

  • navigation - 当前屏幕的导航对象。
  • route - 当前屏幕的路由对象。
  • options - 当前屏幕的选项
  • layout - 屏幕的尺寸,包含 heightwidth 属性。

示例

import { getHeaderTitle } from '@react-navigation/elements';

// ..

header: ({ navigation, route, options }) => {
const title = getHeaderTitle(options, route.name);

return <MyHeader title={title} style={options.headerStyle} />;
};

要为导航器中所有屏幕设置自定义标题,您可以在导航器的 screenOptions 属性中指定此选项。

headerStyle 中指定 height

如果您的自定义标题栏的高度与默认标题栏的高度不同,那么您可能会注意到由于测量是异步的而导致的故障。 显式指定高度将避免此类故障。

示例

headerStyle: {
height: 80, // Specify the height of your custom header
};

请注意,默认情况下,此样式不应用于标题栏,因为您控制自定义标题栏的样式。 如果您还想将此样式应用于您的标题栏,请使用 props 中的 options.headerStyle

headerShown

是否显示或隐藏屏幕的标题栏。 默认情况下显示标题栏。 将此设置为 false 将隐藏标题栏。

事件

导航器可以在某些操作上发出事件。 支持的事件包括:

tabPress

当用户在标签栏中按下当前屏幕的选项卡按钮时,会触发此事件。 默认情况下,选项卡按下会执行以下几项操作:

  • 如果选项卡未聚焦,则选项卡按下将聚焦该选项卡。
  • 如果选项卡已聚焦
    • 如果选项卡的屏幕渲染滚动视图,则可以使用 useScrollToTop 将其滚动到顶部。
    • 如果选项卡的屏幕渲染堆栈导航器,则会在堆栈上执行 popToTop 操作。

要阻止默认行为,您可以调用 event.preventDefault

React.useEffect(() => {
const unsubscribe = navigation.addListener('tabPress', (e) => {
// Prevent default behavior
e.preventDefault();

// Do something manually
// ...
});

return unsubscribe;
}, [navigation]);

如果您有自定义标签栏,请确保发出此事件。

tabLongPress

当用户在标签栏中长时间按下当前屏幕的选项卡按钮时,会触发此事件。 如果您有自定义标签栏,请确保发出此事件。

示例

React.useEffect(() => {
const unsubscribe = navigation.addListener('tabLongPress', (e) => {
// Do something
});

return unsubscribe;
}, [navigation]);

辅助方法

标签导航器将以下方法添加到导航对象:

jumpTo

导航到标签导航器中的现有屏幕。 该方法接受以下参数:

  • name - 字符串 - 要跳转到的路由的名称。
  • params - 对象 - 用于目标路由的屏幕参数。
navigation.jumpTo('Profile', { owner: 'Michaś' });

Hook

底部标签导航器导出以下 Hook:

useBottomTabBarHeight

此 Hook 返回底部标签栏的高度。 默认情况下,屏幕内容不会位于标签栏下方。 但是,如果您想使标签栏绝对定位并将内容放在其下方(例如,显示模糊效果),则有必要调整内容以考虑标签栏高度。

示例

import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';

function MyComponent() {
const tabBarHeight = useBottomTabBarHeight();

return (
<ScrollView contentStyle={{ paddingBottom: tabBarHeight }}>
{/* Content */}
</ScrollView>
);
}

或者,如果您正在使用类组件或需要在可在底部标签导航器外部使用的可重用组件中使用它,则可以直接使用 BottomTabBarHeightContext

import { BottomTabBarHeightContext } from '@react-navigation/bottom-tabs';

// ...

<BottomTabBarHeightContext.Consumer>
{tabBarHeight => (
/* render something */
)}
</BottomTabBarHeightContext.Consumer>

动画

默认情况下,在选项卡之间切换没有任何动画。 您可以指定 animation 选项来自定义过渡动画。

animation 支持的值包括:

  • fade - 屏幕过渡的交叉淡入淡出动画,其中新屏幕淡入,旧屏幕淡出。

  • shift - 屏幕过渡的平移动画,其中屏幕稍微向左/向右移动。

  • none - 屏幕过渡没有任何动画。 这是默认值。

const RootTabs = createBottomTabNavigator({
screenOptions: {
animation: 'fade',
},
screens: {
Home: HomeScreen,
Profile: ProfileScreen,
},
});
Snack 上尝试

如果您需要对动画进行更多控制,则可以使用各种与动画相关的选项来自定义动画的各个部分。

底部标签导航器公开了各种选项,用于配置在切换选项卡时的过渡动画。 这些过渡动画可以在每个屏幕的基础上进行自定义,方法是在每个屏幕的 options 中指定选项,或者通过在 screenOptions 中指定它们来为标签导航器中的所有屏幕自定义。

  • transitionSpec - 一个对象,用于指定动画类型(timingspring)及其选项(例如 timingduration)。 它包含 2 个属性:

    • animation - 用于动画的动画函数。 支持的值为 timingspring
    • config - timing 函数的配置对象。 对于 timing,它可以是 durationeasing。 对于 spring,它可以是 stiffnessdampingmassovershootClampingrestDisplacementThresholdrestSpeedThreshold

    使用 timing 动画的配置如下所示:

    const config = {
    animation: 'timing',
    config: {
    duration: 150,
    easing: Easing.inOut(Easing.ease),
    },
    };

    我们可以在 transitionSpec 选项中传递此配置。

    {
    Profile: {
    screen: Profile,
    options: {
    transitionSpec: {
    animation: 'timing',
    config: {
    duration: 150,
    easing: Easing.inOut(Easing.ease),
    },
    },
    },
    },
    }
  • sceneStyleInterpolator - 这是一个函数,用于指定场景各个部分的插值样式。 它当前支持包含屏幕的视图的样式:

    • sceneStyle - 包装屏幕内容的容器视图的样式。

    该函数在其参数中接收以下属性:

    • current - 当前屏幕的动画值
      • progress - 表示当前屏幕进度值的动画节点。

    淡化屏幕的配置如下所示:

    const forFade = ({ current }) => ({
    sceneStyle: {
    opacity: current.progress.interpolate({
    inputRange: [-1, 0, 1],
    outputRange: [0, 1, 0],
    }),
    },
    });

    current.progress 的值如下:

    • -1 如果索引低于活动选项卡,
    • 0 如果它们处于活动状态,
    • 1 如果索引高于活动选项卡

    我们可以在 sceneStyleInterpolator 选项中传递此函数。

    {
    Profile: {
    screen: Profile,
    options: {
    sceneStyleInterpolator: ({ current }) => ({
    sceneStyle: {
    opacity: current.progress.interpolate({
    inputRange: [-1, 0, 1],
    outputRange: [0, 1, 0],
    }),
    },
    }),
    },
    },
    }

将这些放在一起,您可以自定义屏幕的过渡动画。

const RootTabs = createBottomTabNavigator({
screenOptions: {
transitionSpec: {
animation: 'timing',
config: {
duration: 150,
easing: Easing.inOut(Easing.ease),
},
},
sceneStyleInterpolator: ({ current }) => ({
sceneStyle: {
opacity: current.progress.interpolate({
inputRange: [-1, 0, 1],
outputRange: [0, 1, 0],
}),
},
}),
},
screens: {
Home: HomeScreen,
Profile: ProfileScreen,
},
});
Snack 上尝试

预制配置

我们还从库中导出各种带有预制配置的配置,您可以使用这些配置来自定义动画。

TransitionSpecs

  • FadeSpec - 屏幕之间交叉淡入淡出动画的配置。
  • ShiftSpec - 屏幕之间平移动画的配置。

示例

import { TransitionSpecs } from '@react-navigation/bottom-tabs';

// ...

{
Profile: {
screen: Profile,
options: {
transitionSpec: TransitionSpecs.CrossFadeSpec,
},
},
}

SceneStyleInterpolators

  • forFade - 屏幕过渡的交叉淡入淡出动画,其中新屏幕淡入,旧屏幕淡出。
  • forShift - 屏幕过渡的平移动画,其中屏幕稍微向左/向右移动。

示例

import { SceneStyleInterpolators } from '@react-navigation/bottom-tabs';

// ...

{
Profile: {
screen: Profile,
options: {
sceneStyleInterpolator: SceneStyleInterpolators.forFade,
},
},
}

TransitionPresets

我们导出过渡预设,这些预设将这些选项的各种集合捆绑在一起。 过渡预设是一个对象,其中包含在 TransitionPresets 下导出的几个与动画相关的屏幕选项。 目前,以下预设可用:

  • FadeTransition - 屏幕过渡的交叉淡入淡出动画,其中新屏幕淡入,旧屏幕淡出。
  • ShiftTransition - 屏幕过渡的平移动画,其中屏幕稍微向左/向右移动。

您可以在 options 中展开这些预设,以自定义屏幕的动画。

示例

import { TransitionPresets } from '@react-navigation/bottom-tabs';

// ...

{
Profile: {
screen: Profile,
options: {
...TransitionPresets.FadeTransition,
},
},
}