This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.

栈

编辑页面

了解如何在 Expo Router 中使用 Stack 导航器。


使用 Expo Router 配合 Stack 导航器
使用 Expo Router 配合 Stack 导航器

在屏幕之间导航、在屏幕之间传递参数、创建动态路由,并配置屏幕标题和动画。

Stack 导航器是在应用中路由之间导航的基础方式。在 Android 上,堆叠路由会在当前屏幕上方播放动画。在 iOS 上,堆叠路由会从右侧滑入。Expo Router 提供了一个 Stack 导航组件,用于创建导航堆栈,并允许你在应用中添加新路由。

本指南介绍如何在项目中创建 Stack 导航器,并自定义单个路由的选项和标题栏。

开始使用

你可以使用基于文件的路由来创建 stack 导航器。下面是一个示例文件结构:

src
 app
  _layout.tsx
  index.tsx
  details.tsx

这种文件结构会生成一个布局:其中 index 路由是堆栈中的第一个路由,而 details 路由在导航时会被压到 index 路由之上。

你可以使用 src/app/_layout.tsx 文件来为你的应用定义包含这两个路由的 Stack 导航器:

src/app/_layout.tsx
import { Stack } from 'expo-router'; export default function Layout() { return <Stack />; }

屏幕选项与标题栏配置

从 SDK 55 开始,你可以使用基于 options 的 API 或新的组合组件 API 来配置屏幕选项和标题栏。这两种 API 都可以在你的项目中互换使用。

静态配置路由选项

你可以在布局组件路由中使用 <Stack.Screen name={routeName} /> 组件来静态配置某个路由的选项。

src/app/_layout.tsx
import { Stack } from 'expo-router'; export default function Layout() { return ( <Stack // 有关可用 screenOptions 的更多信息,请参阅 React Navigation 文档:https://reactnavigation.org/docs/headers/#sharing-common-options-across-screens screenOptions={{ headerStyle: { backgroundColor: '#f4511e', }, headerTintColor: '#fff', headerTitleStyle: { fontWeight: 'bold', }, }}> {/* 可选:在路由外部配置静态选项。*/} <Stack.Screen name="home" options={{}} /> </Stack> ); }

配置标题栏

你可以通过使用 screenOptions 属性来配置 Stack 导航器中所有路由的标题栏。这对于在所有路由之间设置统一的标题栏样式很有用。

src/app/_layout.tsx
import { Stack } from 'expo-router'; export default function Layout() { return ( <Stack screenOptions={{ headerStyle: { backgroundColor: '#f4511e', }, headerTintColor: '#fff', headerTitleStyle: { fontWeight: 'bold', }, }} /> ); }

动态设置屏幕选项

要动态配置某个路由的选项,你可以使用组合组件或基于 options 的 API。

src/app/details.tsx
import { Stack, useLocalSearchParams, useRouter } from 'expo-router'; import { View, Text, StyleSheet } from 'react-native'; export default function Details() { const router = useRouter(); const params = useLocalSearchParams(); return ( <View style={styles.container}> <Stack.Screen options={{ title: params.name, headerStyle: { backgroundColor: 'lightblue' }, }} /> <Text onPress={() => { router.setParams({ name: 'Updated' }); }}> 更新标题 </Text> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', }, });

可用的标题栏选项

Stack 导航器支持全面的标题栏配置选项。以下是所有可用的标题栏相关选项:

Header options
OptionPlatformDescription
header
Android
iOS

Custom header to use instead of the default header.

This accepts a function that returns a React Element to display as a header. The function receives an object containing the following properties as the argument:

  • navigation - The navigation object for the current screen.
  • route - The route object for the current screen.
  • options - The options for the current screen
  • back - Options for the back button, contains an object with a title property to use for back button label.

To set a custom header for all the screens in the navigator, you can specify this option in the screenOptions prop of the navigator.

Note that if you specify a custom header, the native functionality such as large title, search bar etc. won't work.

headerBackButtonDisplayMode
iOS

How the back button displays icon and title.

Supported values:

  • "default" - Displays one of the following depending on the available space: previous screen's title, generic title (e.g. 'Back') or no title (only icon).
  • "generic" – Displays one of the following depending on the available space: generic title (e.g. 'Back') or no title (only icon).
  • "minimal" – Always displays only the icon without a title.

The space-aware behavior is disabled when:

  • The iOS version is 13 or lower
  • Custom font family or size is set (e.g. with headerBackTitleStyle)
  • Back button menu is disabled (e.g. with headerBackButtonMenuEnabled)

In such cases, a static title and icon are always displayed.

headerBackButtonMenuEnabled
iOS

Boolean indicating whether to show the menu on longPress of iOS >= 14 back button. Defaults to true.

headerBackground
Android
iOS

Function which returns a React Element to render as the background of the header. This is useful for using backgrounds such as an image or a gradient.

headerBackIcon
Android
iOS

Icon to display in the header as the icon in the back button. Defaults to back icon image for the platform:

  • A chevron on iOS
  • An arrow on Android

Currently only supports image sources.

headerBackTitle
iOS

Title string used by the back button on iOS. Defaults to the previous scene's title, "Back" or arrow icon depending on the available space. See headerBackButtonDisplayMode to read about limitations and customize the behavior.

Use headerBackButtonDisplayMode: "minimal" to hide it.

headerBackTitleStyle
iOS

Style object for header back title. Supported properties:

  • fontFamily
  • fontSize
headerBackVisible
Android
iOS

Whether the back button is visible in the header. You can use it to show a back button alongside headerLeft if you have specified it.

This will have no effect on the first screen in the stack.

headerBlurEffect
iOS

Blur effect for the translucent header. The headerTransparent option needs to be set to true for this to work.

Supported values: extraLight, light, regular, prominent, systemUltraThinMaterial, systemThinMaterial, systemMaterial, systemThickMaterial, systemChromeMaterial, systemUltraThinMaterialLight, systemThinMaterialLight, systemMaterialLight, systemThickMaterialLight, systemChromeMaterialLight, dark, systemUltraThinMaterialDark, systemThinMaterialDark, systemMaterialDark, systemThickMaterialDark, systemChromeMaterialDark

Using both headerBlurEffect and scrollEdgeEffects (>= iOS 26) simultaneously may cause overlapping effects.

headerLargeStyle
iOS

Style of the header when a large title is shown. The large title is shown if headerLargeTitleEnabled is true and the edge of any scrollable content reaches the matching edge of the header.

Supported properties:

  • backgroundColor
headerLargeTitleEnabled
iOS

Whether to enable header with large title which collapses to regular header on scroll. Defaults to false.

For large title to collapse on scroll, the content of the screen should be wrapped in a scrollable view such as ScrollView or FlatList. If the scrollable area doesn't fill the screen, the large title won't collapse on scroll. You also need to specify contentInsetAdjustmentBehavior="automatic" in your ScrollView, FlatList etc.

headerLargeTitleShadowVisible
Android
iOS

Whether drop shadow of header is visible when a large title is shown.

headerLargeTitleStyle
iOS

Style object for large title in header. Supported properties:

  • fontFamily
  • fontSize
  • fontWeight
  • color
headerLeft
Android
iOS

Function which returns a React Element to display on the left side of the header. This replaces the back button. See headerBackVisible to show the back button along side left element. It receives the following properties in the arguments:

  • tintColor - The tint color to apply. Defaults to the theme's primary color.
  • canGoBack - Boolean indicating whether there is a screen to go back to.
  • label - Label text for the button. Usually the title of the previous screen.
  • href - The href to use for the anchor tag on web
headerRight
Android
iOS

Function which returns a React Element to display on the right side of the header. It receives the following properties in the arguments:

  • tintColor - The tint color to apply. Defaults to the theme's primary color.
  • canGoBack - Boolean indicating whether there is a screen to go back to.
headerSearchBarOptions
Android
iOS

Options to render a native search bar. Search bars are rarely static so normally it is controlled by passing an object to headerSearchBarOptions navigation option in the component's body.

On iOS, you also need to specify contentInsetAdjustmentBehavior="automatic" in your ScrollView, FlatList etc. If you don't have a ScrollView, specify headerTransparent: false.

Supported properties are:

ref

Ref to manipulate the search input imperatively. It contains the following methods:

  • focus - focuses the search bar
  • blur - removes focus from the search bar
  • setText - sets the search bar's content to given value
  • clearText - removes any text present in the search bar input field
  • cancelSearch - cancel the search and close the search bar
  • toggleCancelButton - depending on passed boolean value, hides or shows cancel button (only supported on iOS)

autoCapitalize

Controls whether the text is automatically auto-capitalized as it is entered by the user. Possible values:

  • systemDefault
  • none
  • words
  • sentences
  • characters

Defaults to systemDefault which is the same as sentences on iOS and none on Android.

autoFocus

Whether to automatically focus search bar when it's shown. Defaults to false.

barTintColor

The search field background color. By default bar tint color is translucent.

tintColor

The color for the cursor caret and cancel button text.

cancelButtonText

The text to be used instead of default Cancel button text.

Deprecated starting from iOS 26.

disableBackButtonOverride

Whether the back button should close search bar's text input or not. Defaults to false.

hideNavigationBar

Boolean indicating whether to hide the navigation bar during searching.

If left unset, system default is used.

hideWhenScrolling

Boolean indicating whether to hide the search bar when scrolling. Defaults to true.

inputType

The type of the input. Defaults to "text".

Supported values: "text", "phone", "number", "email"

obscureBackground

Boolean indicating whether to obscure the underlying content with semi-transparent overlay.

If left unset, system default is used.

placement

Controls preferred placement of the search bar. Defaults to automatic.

Supported values: automatic, stacked, inline, integrated, integratedButton, integratedCentered

allowToolbarIntegration

Boolean indicating whether the system can place the search bar among other toolbar items on iPhone.

Set this prop to false to prevent the search bar from appearing in the toolbar when placement is automatic, integrated, integratedButton or integratedCentered.

Defaults to true. If placement is set to stacked, the value of this prop will be overridden with false.

Only supported on iOS, starting from iOS 26.

placeholder

Text displayed when search field is empty.

textColor

The color of the text in the search field.

hintTextColor

The color of the hint text in the search field.

headerIconColor

The color of the search and close icons shown in the header

shouldShowHintSearchIcon

Whether to show the search hint icon when search bar is focused. Defaults to true.

onBlur

A callback that gets called when search bar has lost focus.

onCancelButtonPress

A callback that gets called when the cancel button is pressed.

onSearchButtonPress

A callback that gets called when the search button is pressed.

const [search, setSearch] = React.useState(''); React.useLayoutEffect(() => { navigation.setOptions({ headerSearchBarOptions: { onSearchButtonPress: (event) => setSearch(event?.nativeEvent?.text), }, }); }, [navigation]);

onChangeText

A callback that gets called when the text changes. It receives the current text value of the search bar.

headerShown

Whether to show the header. The header is shown by default. Setting this to false hides the header.

headerShadowVisible
Android
iOS

Whether to hide the elevation shadow (Android) or the bottom border (iOS) on the header.

headerShown
Android
iOS

Whether to show the header. The header is shown by default. Setting this to false hides the header.

headerStyle
Android
iOS

Style object for header. Supported properties:

  • backgroundColor
headerTintColor
Android
iOS

Tint color for the header. Changes the color of back button and title.

headerTitle
Android
iOS

String or a function that returns a React Element to be used by the header. Defaults to title or name of the screen.

When a function is passed, it receives tintColor andchildren in the options object as an argument. The title string is passed in children.

Note that if you render a custom element by passing a function, animations for the title won't work.

headerTitleAlign
Android
iOS

How to align the header title. Possible values:

  • left
  • center

Defaults to left on platforms other than iOS.

Not supported on iOS. It's always center on iOS and cannot be changed.

headerTitleStyle
Android
iOS

Style object for header title. Supported properties:

  • fontFamily
  • fontSize
  • fontWeight
  • color
headerTransparent
Android
iOS

Boolean indicating whether the navigation bar is translucent.

Defaults to false. Setting this to true makes the header absolutely positioned - so that the header floats over the screen so that it overlaps the content underneath, and changes the background color to transparent unless specified in headerStyle.

This is useful if you want to render a semi-transparent header or a blurred background.

Note that if you don't want your content to appear under the header, you need to manually add a top margin to your content. React Navigation won't do it automatically.

To get the height of the header, you can use HeaderHeightContext with React's Context API or useHeaderHeight.

title
Android
iOS

String that can be used as a fallback for headerTitle.

unstable_headerInsets
Android

Which edges of the native header apply window insets (e.g. statusbar inset) on Android.

The native header applies insets to every edge by default. Setting an edge to false removes the inset for that edge:

unstable_headerInsets: { top: false, bottom: false, }

Supported edges are top, left, right, and bottom.

Disabling an inset also disables it for nested headers. A nested header cannot re-enable an inset disabled by a parent header.

This API may change in a minor release.

unstable_headerLeftItems
iOS

This option is experimental and may change in a minor release.

Function which returns an array of items to display as on the left side of the header. This will override headerLeft if both are specified. It receives the following properties in the arguments:

  • tintColor - The tint color to apply. Defaults to the theme's primary color.
  • canGoBack - Boolean indicating whether there is a screen to go back to.

See Header items for more information.

unstable_headerRightItems
iOS

This option is experimental and may change in a minor release.

Function which returns an array of items to display as on the right side of the header. This will override headerRight if both are specified. It receives the following properties in the arguments:

  • tintColor - The tint color to apply. Defaults to the theme's primary color.
  • canGoBack - Boolean indicating whether there is a screen to go back to.

See Header items for more information.

如需更多细节和导航器相关示例,请参阅 React Navigation 的 Native Stack Navigator 文档。

标题栏按钮

你可以使用 headerLeft 和 headerRight 选项,或 <Stack.Toolbar> 组件来向标题栏添加按钮。这些选项接收一个会在标题栏中渲染的 React 组件。

Stack 工具栏

配置支持 Liquid Glass 的 iOS 标题栏工具栏。

src/app/index.tsx
import { Stack } from 'expo-router'; import { Button, Text, Image, StyleSheet } from 'react-native'; import { useState } from 'react'; function LogoTitle() { return ( <Image style={styles.image} source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }} /> ); } export default function Home() { const [count, setCount] = useState(0); return ( <> <Stack.Screen options={{ headerTitle: props => <LogoTitle {...props} />, headerRight: () => <Button onPress={() => setCount(c => c + 1)} title="更新计数" />, }} /> <Text>Count: {count}</Text> </> ); } const styles = StyleSheet.create({ image: { width: 50, height: 50, }, });

其他屏幕选项

要查看所有其他可用屏幕选项的完整列表,包括动画、手势和其他配置:

Screen options
OptionPlatformDescription
animation
Android

How the screen should animate when pushed or popped.

Supported values: default, fade, fade_from_bottom, flip, simple_push, slide_from_bottom, slide_from_right, slide_from_left, none

animationDuration
iOS

Changes the duration (in milliseconds) of slide_from_bottom, fade_from_bottom, fade and simple_push transitions on iOS. Defaults to 350.

For screens with default and flip transitions, and, as of now, for screens with presentation set to modal, formSheet, pageSheet (regardless of transition), the duration isn't customizable.

animationMatchesGesture
iOS

Whether the gesture to dismiss should use animation provided to animation prop. Defaults to false.

Doesn't affect the behavior of screens presented modally.

animationTypeForReplace
Android
iOS

The type of animation to use when this screen replaces another screen. Defaults to push.

Supported values: push, pop

This can be useful to provide appropriate animations, such as push for login and pop for logout.

autoHideHomeIndicator
iOS

Boolean indicating whether the home indicator should prefer to stay hidden. Defaults to false.

contentStyle
Android
iOS

Style object for the scene content.

freezeOnBlur
iOS

Boolean indicating whether to prevent inactive screens from re-rendering. Defaults to false. Defaults to true when enableFreeze() from react-native-screens package is run at the top of the application.

Only supported on iOS and Android.

fullScreenGestureEnabled
iOS

Whether the gesture to dismiss should work on the whole screen. Using gesture to dismiss with this option results in the same transition animation as simple_push. This behavior can be changed by setting customAnimationOnGesture prop. Achieving the default iOS animation isn't possible due to platform limitations. Defaults to false.

Doesn't affect the behavior of screens presented modally.

fullScreenGestureShadowEnabled
Android
iOS

Whether the full screen dismiss gesture has shadow under view during transition. Defaults to true.

This does not affect the behavior of transitions that don't use gestures enabled by fullScreenGestureEnabled prop.

gestureDirection
iOS

Sets the direction in which you should swipe to dismiss the screen.

Supported values: vertical, horizontal

When using vertical option, options fullScreenGestureEnabled: true, customAnimationOnGesture: true and animation: 'slide_from_bottom' are set by default.

gestureEnabled
iOS

Whether you can use gestures to dismiss this screen. Defaults to true.

navigationBarColor
Android

This option is deprecated and will be removed in a future release (for apps targeting Android SDK 35 or above edge-to-edge mode is enabled by default and it is expected that the edge-to-edge will be enforced in future SDKs, see here for more information).

Sets the navigation bar color. Defaults to initial status bar color.

navigationBarHidden
Android

Boolean indicating whether the navigation bar should be hidden. Defaults to false.

orientation
Android

The display orientation to use for the screen.

Supported values: default, all, portrait, portrait_up, portrait_down, landscape, landscape_left, landscape_right

presentation
Android

How should the screen be presented.

Supported values: card, modal, containedModal, fullScreenModal, transparentModal, containedTransparentModal, formSheet

scrollEdgeEffects
iOS

Configures the scroll edge effect for the content ScrollView (the ScrollView that is present in first descendants chain of the Screen). Depending on values set, it will blur the scrolling content below certain UI elements (e.g. header items, search bar) for the specified edge of the ScrollView. When set in nested containers, i.e. Native Stack inside Native Bottom Tabs, or the other way around, the ScrollView will use only the innermost one's config.

Edge effects can be configured for each edge separately. The following values are currently supported:

  • automatic - the automatic scroll edge effect style,
  • hard - a scroll edge effect with a hard cutoff and dividing line,
  • soft - a soft-edged scroll edge effect,
  • hidden - no scroll edge effect.

Defaults to automatic for each edge.

Using both blurEffect and scrollEdgeEffects (>= iOS 26) simultaneously may cause overlapping effects.

Only supported on iOS, starting from iOS 26.

sheetAllowedDetents
Android

Describes heights where a sheet can rest.

Supported values: 'fitToContents' or an array of fractions (e.g. [0.25, 0.5, 0.75]). The array must be sorted in ascending order. This invariant is verified only in development mode, where violation results in an error. Android is limited to 3 detents.

Defaults to [1.0].

See Configuring sheet sizes for usage examples.

sheetCornerRadius
Android

The corner radius of the sheet. If set to a non-negative value it will use the provided radius, otherwise the system default is used.

sheetElevation
Android

Integer value describing elevation of the sheet, impacting shadow on the top edge.

Not dynamic - changing it after the component is rendered won't have an effect.

Defaults to 24.

sheetExpandsWhenScrolledToEdge
iOS

Whether the sheet should expand to a larger detent when scrolling.

The ScrollView must be reachable by following the first child view at each level of the view hierarchy from the screen component.

Defaults to true.

See Scroll behavior for more details.

sheetGrabberVisible
iOS

Whether the sheet shows a grabber handle at the top.

Defaults to false.

sheetInitialDetentIndex
Android

Index of the detent the sheet should expand to after being opened. If the specified index is out of bounds of the sheetAllowedDetents array, an error will be thrown in development mode and the value will be reset to the default in production.

Can also be set to 'last' to open at the largest detent.

Defaults to 0.

See Configuring sheet sizes for usage examples.

sheetLargestUndimmedDetentIndex
Android

The largest detent index for which the view underneath won't be dimmed.

Can be set to a number (index into sheetAllowedDetents), 'none' (always dim), or 'last' (never dim).

Defaults to 'none'.

See Controlling dimming for usage examples.

sheetResizeAnimationEnabled
Android

Whether the default native animation should be used when the sheet's content size changes (specifically when using fitToContents).

Set to false to implement custom resizing animations.

Defaults to true.

sheetShouldOverflowTopInset
Android

Whether the sheet content should be rendered behind the status bar or display cutouts.

When true, detent ratios in sheetAllowedDetents are measured relative to the full stack height. When false, they are measured relative to the adjusted height (excluding the top inset).

Defaults to false.

statusBarAnimation
Android

Sets the status bar animation (similar to the StatusBar component). Defaults to fade on iOS and none on Android.

Supported values: "fade", "none", "slide"

On Android, setting either fade or slide will set the transition of status bar color. On iOS, this option applies to the appearance animation of the status bar.

Requires setting View controller-based status bar appearance -> YES (or removing the config) in your Info.plist file.

statusBarBackgroundColor
Android

This option is deprecated and will be removed in a future release (for apps targeting Android SDK 35 or above edge-to-edge mode is enabled by default and it is expected that the edge-to-edge will be enforced in future SDKs, see here for more information).

Sets the background color of the status bar (similar to the StatusBar component).

statusBarHidden
Android

Whether the status bar should be hidden on this screen.

Requires setting View controller-based status bar appearance -> YES (or removing the config) in your Info.plist file.

statusBarStyle
Android

Sets the status bar color (similar to the StatusBar component).

Supported values: "auto", "inverted", "dark", "light"

Defaults to auto on iOS and light on Android.

Requires setting View controller-based status bar appearance -> YES (or removing the config) in your Info.plist file.

statusBarTranslucent
Android

This option is deprecated and will be removed in a future release (for apps targeting Android SDK 35 or above edge-to-edge mode is enabled by default and it is expected that the edge-to-edge will be enforced in future SDKs, see here for more information).

Sets the translucency of the status bar (similar to the StatusBar component). Defaults to false.

tabBarAccessibilityLabel
Android
iOS

Accessibility label for the tab button. This is read by the screen reader when the user taps the tab. It's recommended to set this if you don't have a label for the tab.

tabBarActiveBackgroundColor
Android
iOS

Background color for the active tab.

tabBarActiveTintColor
Android
iOS

Color for the icon and label in the active tab.

tabBarBackground
Android
iOS

Function which returns a React Element to use as background for the tab bar. You could render an image, a gradient, blur view etc.:

import { BlurView } from 'expo-blur'; import { StyleSheet } from 'react-native'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; // ... createBottomTabNavigator({ screenOptions: { tabBarStyle: { position: 'absolute' }, tabBarBackground: () => ( <BlurView tint="light" intensity={100} style={StyleSheet.absoluteFill} /> ), }, screens: { // ... }, });
import { BlurView } from 'expo-blur'; import { StyleSheet } from 'react-native'; // ... <Tab.Navigator screenOptions={{ tabBarStyle: { position: 'absolute' }, tabBarBackground: () => ( <BlurView tint="light" intensity={100} style={StyleSheet.absoluteFill} /> ), }} >

When using BlurView, make sure to set position: 'absolute' in tabBarStyle as well. You'd also need to use useBottomTabBarHeight to add bottom padding to your content.

tabBarBadge
Android
iOS

Text to show in a badge on the tab icon. Accepts a string or a number.

tabBarBadgeStyle
Android
iOS

Style for the badge on the tab icon. You can specify a background color or text color here.

tabBarButton
Android
iOS

Function which returns a React element to render as the tab bar button. It wraps the icon and label. Renders PlatformPressable by default.

You can specify a custom implementation here:

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

ID to locate this tab button in tests.

tabBarHideOnKeyboard
Android
iOS

Whether the tab bar is hidden when the keyboard opens. Defaults to false.

tabBarIcon
Android
iOS

Function that given { focused: boolean, color: string, size: number } returns a React.Node, to display in the tab bar.

tabBarIconStyle
Android
iOS

Style object for the tab icon.

tabBarInactiveBackgroundColor
Android
iOS

Background color for the inactive tabs.

tabBarInactiveTintColor
Android
iOS

Color for the icon and label in the inactive tabs.

tabBarItemStyle
Android
iOS

Style object for the tab item container.

tabBarLabel
Android
iOS

Title string of a tab displayed in the tab bar or a function that given { focused: boolean, color: string } returns a React.Node, to display in tab bar. When undefined, scene title is used. To hide, see tabBarShowLabel.

tabBarLabelPosition
Android
iOS

Whether the label is shown below the icon or beside the icon. By default, the position is chosen automatically based on device width.

  • below-icon

    The label is shown below the icon (typical for devices with smaller widths such as phones)

  • beside-icon

    The label is shown next to the icon (typical for larger devices such as tablets)

tabBarLabelStyle
Android
iOS

Style object for the tab label.

tabBarPosition
Android
iOS

Position of the tab bar. Available values are:

  • bottom (Default)
  • top
  • left
  • right

When the tab bar is positioned on the left or right, it is styled as a sidebar. This can be useful when you want to show a sidebar on larger screens and a bottom tab bar on smaller screens:

You can also render a compact sidebar by placing the label below the icon. This is only supported when the tabBarVariant is set to material:

tabBarShowLabel
Android
iOS

Whether the tab label should be visible. Defaults to true.

tabBarStyle
Android
iOS

Style object for the tab bar. You can configure styles such as background color here.

To show your screen under the tab bar, you can set the position style to absolute:

createBottomTabNavigator({ screenOptions: { tabBarStyle: { position: 'absolute' }, }, screens: { // ... }, });
<Tab.Navigator screenOptions={{ tabBarStyle: { position: 'absolute' }, }} >

You also might need to add a bottom margin to your content if you have an absolutely positioned tab bar. React Navigation won't do it automatically. See useBottomTabBarHeight for more details.

tabBarVariant
Android
iOS

Variant of the tab bar. Available values are:

  • uikit (Default) - The tab bar will be styled according to the iOS UIKit guidelines.
  • material - The tab bar will be styled according to the Material Design guidelines.

The material variant is currently only supported when the tabBarPosition is set to left or right.

如需更多细节和导航器相关示例,请参阅 React Navigation 的 Native Stack Navigator 文档。

自定义 push 行为

默认情况下,当 Stack 导航器在栈中 push 一个已存在的路由时,会移除重复的屏幕。例如,如果你连续 push 同一个屏幕两次,第二次 push 会被忽略。你可以通过向 <Stack.Screen> 提供自定义 getId() 函数来更改这种 push 行为。

例如,下面布局结构中的 index 路由展示了应用中不同用户资料的列表。让我们把 [details] 路由改成一个动态路由,这样应用用户就可以导航查看某个资料的详情。

src
 app
  _layout.tsx
  index.tsx
  [details].tsx匹配类似 '/details1' 的动态路径

每次应用用户导航到不同资料时,Stack 导航器都会 push 一个新屏幕,但会失败。如果你提供一个每次都返回新 ID 的 getId() 函数,Stack 就会在应用用户每次导航到资料页时 push 一个新屏幕。

你可以在布局组件路由中使用 <Stack.Screen name="[profile]" getId={}> 组件来修改 push 行为:

src/app/_layout.tsx
import { Stack } from 'expo-router'; export default function Layout() { return ( <Stack> <Stack.Screen name="[profile]" getId={ ({ params }) => String(Date.now()) } /> </Stack> ); }

移除堆栈屏幕

你可以使用不同的操作来关闭并移除堆栈中的一个或多个路由。

dismiss 操作

关闭最近的堆栈中的最后一个屏幕。如果当前屏幕是堆栈中的唯一路由,则会关闭整个堆栈。

你也可以传入一个正数,表示最多关闭指定数量的屏幕。

dismiss 与 back 不同,因为它针对的是最近的堆栈,而不是当前导航器。如果你有嵌套导航器,调用 dismiss 会让你返回多个屏幕。

src/app/settings.tsx
import { Button, View } from 'react-native'; import { useRouter } from 'expo-router'; export default function Settings() { const router = useRouter(); const handleDismiss = (count: number) => { router.dismiss(count) }; return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Button title="回到第一屏" onPress={() => handleDismiss(3)} /> </View> ); }

dismissTo 操作

关闭当前 <Stack /> 中的屏幕,直到到达指定的 Href。如果历史记录中不存在该 Href,则会将当前屏幕替换为指定的 Href。

例如,假设路由 /one、/two、/three 的历史记录中,/three 是当前路由。操作 router.dismissTo('/one') 会使历史记录回退两次,而 router.dismissTo('/four') 会将当前的 /three 路由替换为 /four 路由。

src/app/settings.tsx
import { Button, View, Text } from 'react-native'; import { useRouter } from 'expo-router'; export default function Settings() { const router = useRouter(); const handleDismissAll = () => { router.dismissTo('/') }; return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Button title="回到第一屏" onPress={handleDismissAll} /> </View> ); }

dismissAll 操作

返回到最近堆栈中的第一屏。这类似于 popToTop 堆栈操作。

例如,home 路由是第一屏,而 settings 是最后一屏。要从 settings 回到 home 路由,你必须先回到 details。然而,使用 dismissAll 操作后,你可以从 settings 回到 home,并关闭中间的任意屏幕。

src/app/settings.tsx
import { Button, View, Text } from 'react-native'; import { useRouter } from 'expo-router'; export default function Settings() { const router = useRouter(); const handleDismissAll = () => { router.dismissAll() }; return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Button title="回到第一屏" onPress={handleDismissAll} /> </View> ); }

canDismiss 操作

用于检查当前屏幕是否可以被关闭。如果 router 处于一个堆栈中,且堆栈历史中有超过一个屏幕,则返回 true。

src/app/settings.tsx
import { Button, View } from 'react-native'; export default function Settings() { const router = useRouter(); const handleDismiss = (count: number) => { if (router.canDismiss()) { router.dismiss(count) } }; return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Button title="可能关闭" onPress={() => handleDismiss()} /> </View> ); }

iOS 26 Liquid Glass 标题栏

从 iOS 26 开始,导航标题栏默认采用系统的 “Liquid Glass” 效果。它不能按单个屏幕禁用,因此你需要通过全局配置来关闭它。

方法 1:使用 UIDesignRequiresCompatibility

创建一个开发版本,并在应用配置中将 UIDesignRequiresCompatibility 属性设置为 true:

app.json
{ "ios": { "infoPlist": { "UIDesignRequiresCompatibility": true } } }

方法 2:使用基于 JavaScript 的导航栈

将原生栈替换为位于 expo-router/js-stack 的 JavaScript 驱动栈。这样你就可以完全控制标题栏 UI,但代价是失去高度优化的 iOS 导航视图和控制器带来的性能优势:

src/app/_layout.tsx
import { Stack as JsStack } from 'expo-router/js-stack'; export default function Layout() { return <JsStack />; }

expo-router/js-stack 入口是 SDK 56 中对 @react-navigation/stack 库的替代方案。有关更多信息,请参阅 SDK 55 到 56 迁移指南。

常见问题

滚动时大标题不会折叠

当使用 headerLargeTitle: true(或 <Stack.Title large>)配合 ScrollView 或 FlatList 时,大标题可能不会在滚动时折叠。这通常发生在可滚动视图不是屏幕组件直接第一个子元素的时候。

要修复此问题,请确保 ScrollView 或 FlatList 是由屏幕组件直接渲染的第一个子元素。如果你需要一个包装容器,请在其上设置 collapsable={false}:

src/app/index.tsx
import { Stack } from 'expo-router'; import { ScrollView, View, Text } from 'react-native'; export default function Home() { return ( <ScrollView> <Stack.Title large>Home</Stack.Title> <Text>Content here</Text> </ScrollView> ); }

如果你需要包裹 ScrollView,请在包装容器上设置 collapsable={false}:

src/app/index.tsx
import { Stack } from 'expo-router'; import { ScrollView, View, Text } from 'react-native'; export default function Home() { return ( <View collapsable={false}> <ScrollView> <Stack.Title large>Home</Stack.Title> <Text>Content here</Text> </ScrollView> </View> ); }
在屏幕之间导航时白色背景闪烁

屏幕切换之间出现白色闪烁,通常意味着导航堆栈使用的是浅色背景,而你的应用使用的是深色主题。

要修复此问题,请使用 Expo Router 的 <ThemeProvider> 包裹你的根布局,并传入合适的主题:

src/app/_layout.tsx
import { ThemeProvider, DarkTheme, DefaultTheme, Stack } from 'expo-router'; import { useColorScheme } from 'react-native'; export default function RootLayout() { const colorScheme = useColorScheme(); return ( <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}> <Stack /> </ThemeProvider> ); }

对于始终使用深色主题的应用:

src/app/_layout.tsx
import { ThemeProvider, DarkTheme, Stack } from 'expo-router'; export default function RootLayout() { return ( <ThemeProvider value={DarkTheme}> <Stack /> </ThemeProvider> ); }