Skip to main content
Version: 6.x

堆栈导航器

Stack Navigator 为你的应用提供了一种在屏幕之间进行转换的方法,其中每个新屏幕都放置在堆栈顶部。

¥Stack Navigator provides a way for your app to transition between screens where each new screen is placed on top of a stack.

默认情况下,堆栈导航器配置为具有熟悉的 iOS 和 Android 外观和感觉:iOS 上新屏幕从右侧滑入,Android 上使用操作系统默认动画。但 动画可以定制 可以满足你的需求。

¥By default the stack navigator is configured to have the familiar iOS and Android look & feel: new screens slide in from the right on iOS, use OS default animation on Android. But the animations can be customized to match your needs.

需要记住的一件事是,虽然 @react-navigation/stack 是高度可定制的,但它是用 JavaScript 实现的。虽然它使用原生运行动画和手势,但性能可能不如原生实现那么快。对于很多应用来说这可能不是问题,但如果你在导航过程中遇到性能问题,请考虑使用 @react-navigation/native-stack - 它使用原生导航原语。

¥One thing to keep in mind is that while @react-navigation/stack is extremely customizable, it's implemented in JavaScript. While it runs animations and gestures using natively, the performance may not be as fast as a native implementation. This may not be an issue for a lot of apps, but if you're experiencing performance issues during navigation, consider using @react-navigation/native-stack instead - which uses native navigation primitives.

安装

¥Installation

要使用此导航器,请确保你有 @react-navigation/native 及其依赖(遵循本指南),然后安装 @react-navigation/stack

¥To use this navigator, ensure that you have @react-navigation/native and its dependencies (follow this guide), then install @react-navigation/stack:

npm install @react-navigation/stack

然后,你需要安装和配置堆栈导航器所需的库:

¥Then, you need to install and configure the libraries that are required by the stack navigator:

  1. 首先,安装 react-native-gesture-handler

    ¥First, install react-native-gesture-handler.

    如果你有 Expo 托管项目,请在项目目录中运行:

    ¥If you have a Expo managed project, in your project directory, run:

    npx expo install react-native-gesture-handler

    如果你有一个裸露的 React Native 项目,请在项目目录中运行:

    ¥If you have a bare React Native project, in your project directory, run:

    npm install react-native-gesture-handler
  2. 要完成 react-native-gesture-handler 的安装,请在条目文件的顶部添加以下内容(确保它位于顶部且前面没有其他内容),例如 index.jsApp.js

    ¥To finalize installation of react-native-gesture-handler, add the following at the top (make sure it's at the top and there's nothing else before it) of your entry file, such as index.js or App.js:

    import 'react-native-gesture-handler';

    :::warning 警告

    如果你正在为 Android 或 iOS 进行构建,请不要跳过此步骤,否则即使你的应用在开发中运行良好,也可能会在生产中崩溃。这不适用于其他平台。

    ¥If you are building for Android or iOS, do not skip this step, or your app may crash in production even if it works fine in development. This is not applicable to other platforms.

    :::

  3. 你还可以选择安装 @react-native-masked-view/masked-view。如果你想对标题使用 UIKit 风格的动画 (HeaderStyleInterpolators.forUIKit),则需要这样做。

    ¥Optionally, you can also install @react-native-masked-view/masked-view. This is needed if you want to use UIKit style animations for the header (HeaderStyleInterpolators.forUIKit).

    如果你有 Expo 托管项目,请在项目目录中运行:

    ¥If you have a Expo managed project, in your project directory, run:

    npx expo install @react-native-masked-view/masked-view

    如果你有一个裸露的 React Native 项目,请在项目目录中运行:

    ¥If you have a bare React Native project, in your project directory, run:

    npm install @react-native-masked-view/masked-view
  4. 如果你使用的是 Mac 并针对 iOS 进行开发,则还需要安装 pod(通过 可可足类)来完成链接。

    ¥If you're on a Mac and developing for iOS, you also need to install the pods (via Cocoapods) to complete the linking.

npx pod-install ios

API 定义

¥API Definition

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

¥To use this navigator, import it from @react-navigation/stack:

import { createStackNavigator } from '@react-navigation/stack';

const Stack = createStackNavigator();

function MyStack() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Notifications" component={Notifications} />
<Stack.Screen name="Profile" component={Profile} />
<Stack.Screen name="Settings" component={Settings} />
</Stack.Navigator>
);
}

属性

¥Props

Stack.Navigator 组件接受以下属性:

¥The Stack.Navigator component accepts following props:

id

导航器的可选唯一 ID。这可以与 navigation.getParent 一起使用来在子导航器中引用该导航器。

¥Optional unique ID for the navigator. This can be used with navigation.getParent to refer to this navigator in a child navigator.

initialRouteName

首次加载导航器时要呈现的路由的名称。

¥The name of the route to render on first load of the navigator.

screenOptions

用于导航器屏幕的默认选项。

¥Default options to use for the screens in the navigator.

detachInactiveScreens

布尔值用于指示是否应从视图层次结构中分离非活动屏幕以节省内存。这使得能够与 react-native-screens 集成。默认为 true

¥Boolean used to indicate whether inactive screens should be detached from the view hierarchy to save memory. This enables integration with react-native-screens. Defaults to true.

如果你需要针对特定​​屏幕禁用此优化(例如,你希望屏幕即使在未聚焦时也保持在视图中)detachPreviousScreen 选项。

¥If you need to disable this optimization for specific screens (e.g. you want to screen to stay in view even when unfocused) detachPreviousScreen option.

选项

¥Options

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

¥The following options can be used to configure the screens in the navigator. These can be specified under screenOptions prop of Stack.navigator or options prop of Stack.Screen.

title

可用作 headerTitle 后备的字符串。

¥String that can be used as a fallback for headerTitle.

cardShadowEnabled

使用此属性可以在过渡期间产生可见的阴影。默认为 true

¥Use this prop to have visible shadows during transitions. Defaults to true.

cardOverlayEnabled

使用此属性可在过渡期间在卡片下方显示半透明的深色覆盖层。Android 上默认为 true,iOS 上默认为 false

¥Use this prop to have a semi-transparent dark overlay visible under the card during transitions. Defaults to true on Android and false on iOS.

cardOverlay

返回一个 React 元素以显示为卡片叠加层的函数。使用时请务必将 cardOverlayEnabled 设置为 true

¥Function which returns a React Element to display as the overlay for the card. Make sure to set cardOverlayEnabled to true when using this.

cardStyle

堆栈中卡片的样式对象。你可以在此处提供自定义背景颜色来代替默认背景。

¥Style object for the card in stack. You can provide a custom background color to use instead of the default background here.

你还可以指定 { backgroundColor: 'transparent' } 以使前一个屏幕在下方可见(对于透明模态)。这对于实现模式对话框之类的东西很有用。使用透明背景时,你还应该在选项中指定 presentation: 'modal',这样以前的屏幕就不会分离并在下面保持可见。

¥You can also specify { backgroundColor: 'transparent' } to make the previous screen visible underneath (for transparent modals). This is useful to implement things like modal dialogs. You should also specify presentation: 'modal' in the options when using a transparent background so previous screens aren't detached and stay visible underneath.

在网络上,屏幕的高度不限于视口的高度。这是设计使然,允许浏览器的地址栏在滚动时隐藏。如果这不是理想的行为,你可以将 cardStyle 设置为 { flex: 1 } 以强制屏幕填充视口。

¥On Web, the height of the screen isn't limited to the height of the viewport. This is by design to allow the browser's address bar to hide when scrolling. If this isn't desirable behavior, you can set cardStyle to { flex: 1 } to force the screen to fill the viewport.

presentation

这是快捷方式选项,它配置了几个选项来配置渲染和过渡的样式:

¥This is shortcut option which configures several options to configure the style for rendering and transitions:

  • card:使用 iOS 和 Android 屏幕转换的默认操作系统动画。

    ¥card: Use the default OS animations for iOS and Android screen transitions.

  • modal:使用模态动画。这改变了一些事情:

    ¥modal: Use Modal animations. This changes a few things:

    • 除非另有指定,否则将屏幕设置为 headerModescreen

      ¥Sets headerMode to screen for the screen unless specified otherwise.

    • 更改屏幕动画以匹配模态的平台行为。

      ¥Changes the screen animation to match the platform behavior for modals.

  • transparentModal:与 modal 类似。这会改变以下内容:

    ¥transparentModal: Similar to modal. This changes following things:

    • 除非另有指定,否则将屏幕设置为 headerModescreen

      ¥Sets headerMode to screen for the screen unless specified otherwise.

    • 将屏幕的背景颜色设置为透明,以便上一屏幕可见

      ¥Sets background color of the screen to transparent, so previous screen is visible

    • 调整 detachPreviousScreen 选项,以便保持渲染前一个屏幕。

      ¥Adjusts the detachPreviousScreen option so that the previous screen stays rendered.

    • 防止上一个屏幕从其最后位置开始动画。

      ¥Prevents the previous screen from animating from its last position.

    • 将屏幕动画更改为垂直滑动动画。

      ¥Changes the screen animation to a vertical slide animation.

有关如何自定义 transparentModal 的更多详细信息,请参阅 透明模态框

¥See Transparent modals for more details on how to customize transparentModal.

animationEnabled

是否应在屏幕上启用过渡动画。如果将其设置为 false,则按下或弹出时屏幕不会出现动画。在 iOS 和 Android 上默认为 true,在 Web 上默认为 false

¥Whether transition animation should be enabled on the screen. If you set it to false, the screen won't animate when pushing or popping. Defaults to true on iOS and Android, false on Web.

animationTypeForReplace

当此屏幕替换另一个屏幕时要使用的动画类型。它采用以下值:

¥The type of animation to use when this screen replaces another screen. It takes the following values:

  • push - 将使用新屏幕被推送的动画

    ¥push - The animation of a new screen being pushed will be used

  • pop - 将使用弹出屏幕的动画

    ¥pop - The animation of a screen being popped will be used

默认为 push

¥Defaults to push.

当使用 pop 时,pop 动画将应用于被替换的屏幕。

¥When pop is used, the pop animation is applied to the screen being replaced.

gestureEnabled

是否可以使用手势来关闭此屏幕。iOS 上默认为 true,Android 上默认为 false

¥Whether you can use gestures to dismiss this screen. Defaults to true on iOS, false on Android.

Web 上不支持手势。

¥Gestures are not supported on Web.

gestureResponseDistance

用于覆盖从屏幕边缘开始识别手势的触摸距离的数字。

¥Number to override the distance of touch start from the edge of the screen to recognize gestures.

它将根据 gestureDirection 值配置水平或垂直距离。

¥It'll configure either the horizontal or vertical distance based on the gestureDirection value.

默认值为:

¥The default values are:

  • 50 - 当 gestureDirectionhorizontalhorizontal-inverted

    ¥50 - when gestureDirection is horizontal or horizontal-inverted

  • 135 - 当 gestureDirectionverticalvertical-inverted

    ¥135 - when gestureDirection is vertical or vertical-inverted

Web 上不支持此功能。

¥This is not supported on Web.

gestureVelocityImpact

确定手势速度相关性的数字。默认为 0.3。

¥Number which determines the relevance of velocity for the gesture. Defaults to 0.3.

Web 上不支持此功能。

¥This is not supported on Web.

gestureDirection

手势的方向。详情请参阅 动画部分

¥Direction of the gestures. Refer the Animations section for details.

Web 上不支持此功能。

¥This is not supported on Web.

transitionSpec

屏幕转换的配置对象。详情请参阅 动画部分

¥Configuration object for the screen transition. Refer the Animations section for details.

cardStyleInterpolator

卡片各个部分的插值样式。详情请参阅 动画部分

¥Interpolated styles for various parts of the card. Refer the Animations section for details.

headerStyleInterpolator

标题各个部分的插值样式。详情请参阅 动画部分

¥Interpolated styles for various parts of the header. Refer the Animations section for details.

keyboardHandlingEnabled

如果为 false,则从该屏幕导航到新屏幕时键盘不会自动关闭。默认为 true

¥If false, the keyboard will NOT automatically dismiss when navigating to a new screen from this screen. Defaults to true.

detachPreviousScreen

布尔值用于指示是否从视图层次结构中分离上一个屏幕以节省内存。如果你需要通过活动屏幕看到上一屏幕,请将其设置为 false。仅当 detachInactiveScreens 未设置为 false 时才适用。

¥Boolean used to indicate whether to detach the previous screen from the view hierarchy to save memory. Set it to false if you need the previous screen to be seen through the active screen. Only applicable if detachInactiveScreens isn't set to false.

当使用 presentation 作为 transparentModalmodal 时,会自动调整以保持所需屏幕可见。其他情况下默认为 true

¥This is automatically adjusted when using presentation as transparentModal or modal to keep the required screens visible. Defaults to true in other cases.

freezeOnBlur

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

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

需要 react-native-screens 版本 >=3.16.0。

¥Requires react-native-screens version >=3.16.0.

仅支持 iOS 和 Android。

¥Only supported on iOS and Android.

¥Header related options

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

¥You can find the list of header related options here. These options can be specified under screenOptions prop of Stack.navigator or options prop of Stack.Screen. You don't have to be using @react-navigation/elements directly to use these options, they are just documented in that page.

除此之外,堆栈还支持以下选项:

¥In addition to those, the following options are also supported in stack:

使用自定义标头代替默认标头。

¥Custom header to use instead of the default header.

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

¥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 - 当前屏幕的导航对象。

    ¥navigation - The navigation object for the current screen.

  • route - 当前屏幕的路由对象。

    ¥route - The route object for the current screen.

  • options - 当前屏幕的选项

    ¥options - The options for the current screen

  • layout - 屏幕尺寸,包含 heightwidth 属性。

    ¥layout - Dimensions of the screen, contains height and width properties.

  • progress 代表动画进度的动画节点。

    ¥progress Animated nodes representing the progress of the animation.

  • back - 后退按钮的选项,包含一个具有 title 属性的对象,用于后退按钮标签。

    ¥back - Options for the back button, contains an object with a title property to use for back button label.

  • styleInterpolator - 返回标题中各种元素的插值样式的函数。

    ¥styleInterpolator - Function which returns interpolated styles for various elements in the header.

使用自定义标头时,请确保将 headerMode 也设置为 screen(有关更多详细信息,请参阅下文)。

¥Make sure to set headerMode to screen as well when using a custom header (see below for more details).

示例:

¥Example:

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

// ..

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

return (
<MyHeader
title={title}
leftButton={
back ? <MyBackButton onPress={navigation.goBack} /> : undefined
}
style={options.headerStyle}
/>
);
};

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

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

使用自定义标头时,需要记住两件事:

¥When using a custom header, there are 2 things to keep in mind:

headerStyle 中指定 height 以避免出现故障

¥Specify a height in headerStyle to avoid glitches

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

¥If your header's height differs from the default header height, then you might notice glitches due to measurement being async. Explicitly specifying the height will avoid such glitches.

示例:

¥Example:

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

请注意,默认情况下,此样式不会应用于标头,因为你可以控制自定义标头的样式。如果你也想将此样式应用于标题,请使用 props 中的 headerStyle

¥Note that this style is not applied to the header by default since you control the styling of your custom header. If you also want to apply this style to your header, use headerStyle from the props.

headerMode 设置为 float 以实现自定义标题动画

¥Set headerMode to float for custom header animations

默认情况下,有一个浮动标题,可在 iOS 上的非模态页面上呈现多个屏幕的标题。这些标题包含可以平滑地相互切换的动画。

¥By default, there is one floating header which renders headers for multiple screens on iOS for non-modals. These headers include animations to smoothly switch to one another.

如果你指定自定义标题,React Navigation 会自动将其更改为 screen,以便标题随屏幕一起动画化。这意味着你不必单独实现动画来为其设置动画。

¥If you specify a custom header, React Navigation will change it to screen automatically so that the header animated along with the screen instead. This means that you don't have to implement animations to animate it separately.

但你可能希望保留浮动标题,以便在标题之间具有不同的过渡动画。为此,你需要在选项中指定 headerMode: 'float',然后在自定义标头中插入 progress.currentprogress.next 属性。例如,以下将交叉淡入淡出标题:

¥But you might want to keep the floating header to have a different transition animation between headers. To do that, you'll need to specify headerMode: 'float' in the options, and then interpolate on the progress.current and progress.next props in your custom header. For example, following will cross-fade the header:

const opacity = Animated.add(progress.current, progress.next || 0).interpolate({
inputRange: [0, 1, 2],
outputRange: [0, 1, 0],
});

return (
<Animated.View style={{ opacity }}>{/* Header content */}</Animated.View>
);

headerMode

指定标题应如何呈现:

¥Specifies how the header should be rendered:

  • float - 渲染单个标题,该标题保留在顶部并在屏幕更改时呈现动画。这是 iOS 上的默认设置。

    ¥float - Render a single header that stays at the top and animates as screens are changed. This is default on iOS.

  • screen - 每个屏幕都附有一个标题,并且该标题与屏幕一起淡入和淡出。这是其他平台上的默认设置。

    ¥screen - Each screen has a header attached to it and the header fades in and out together with the screen. This is default on other platforms.

headerShown

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

¥Whether to show or hide the header for the screen. The header is shown by default. Setting this to false hides the header.

headerBackAllowFontScaling

后退按钮标题字体是否应缩放以尊重文本大小辅助功能设置。默认为 false。

¥Whether back button title font should scale to respect Text Size accessibility settings. Defaults to false.

headerBackAccessibilityLabel

标题后退按钮的辅助功能标签。

¥Accessibility label for the header back button.

headerBackImage

返回 React 元素以在标题的后退按钮中显示自定义图片的函数。当使用函数时,它会在其参数对象中接收 tintColor。默认为具有背面图片源的图片组件,这是平台的默认背面图标图片(iOS 上为 V 形,Android 上为箭头)。

¥Function which returns a React Element to display custom image in header's back button. When a function is used, it receives the tintColor in it's argument object. Defaults to Image component with back image source, which is the default back icon image for the platform (a chevron on iOS and an arrow on Android).

headerBackTitle

iOS 上后退按钮使用的标题字符串。默认为前一个场景的 headerTitle

¥Title string used by the back button on iOS. Defaults to the previous scene's headerTitle.

headerBackTitleVisible

为后退按钮标题是否可见提供了合理的默认值,但如果你想覆盖该默认值,可以在此选项中使用 truefalse

¥A reasonable default is supplied for whether the back button title should be visible or not, but if you want to override that you can use true or false in this option.

headerTruncatedBackTitle

headerBackTitle 不适合屏幕时后退按钮使用的标题字符串。默认为 "Back"

¥Title string used by the back button when headerBackTitle doesn't fit on the screen. "Back" by default.

headerBackTitleStyle

后标题的样式对象。

¥Style object for the back title.

活动

¥Events

导航器可以对某些操作进行 触发事件。支持的事件有:

¥The navigator can emit events on certain actions. Supported events are:

transitionStart

当前屏幕的过渡动画开始时会触发此事件。

¥This event is fired when the transition animation starts for the current screen.

事件数据:

¥Event data:

  • e.data.closing - 布尔值,指示屏幕是否正在打开或关闭。

    ¥e.data.closing - Boolean indicating whether the screen is being opened or closed.

示例:

¥Example:

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

return unsubscribe;
}, [navigation]);

transitionEnd

当前屏幕的过渡动画结束时会触发此事件。

¥This event is fired when the transition animation ends for the current screen.

事件数据:

¥Event data:

  • e.data.closing - 指示屏幕是打开还是关闭的布尔值。

    ¥e.data.closing - Boolean indicating whether the screen was opened or closed.

示例:

¥Example:

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

return unsubscribe;
}, [navigation]);

gestureStart

当当前屏幕开始滑动手势时会触发此事件。

¥This event is fired when the swipe gesture starts for the current screen.

示例:

¥Example:

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

return unsubscribe;
}, [navigation]);

gestureEnd

当前屏幕的滑动手势结束时会触发此事件。例如屏幕已成功关闭。

¥This event is fired when the swipe gesture ends for the current screen. e.g. a screen was successfully dismissed.

示例:

¥Example:

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

return unsubscribe;
}, [navigation]);

gestureCancel

当当前屏幕的滑动手势被取消时,会触发此事件。例如该手势并未关闭屏幕。

¥This event is fired when the swipe gesture is cancelled for the current screen. e.g. a screen wasn't dismissed by the gesture.

示例:

¥Example:

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

return unsubscribe;
}, [navigation]);

帮手

¥Helpers

堆栈导航器将以下方法添加到导航属性中:

¥The stack navigator adds the following methods to the navigation prop:

replace

将当前屏幕替换为堆栈中的新屏幕。该方法接受以下参数:

¥Replaces the current screen with a new screen in the stack. The method accepts following arguments:

  • name - string - 要推入堆栈的路由名称。

    ¥name - string - Name of the route to push onto the stack.

  • params - object - 屏幕参数传递到目标路由。

    ¥params - object - Screen params to pass to the destination route.

navigation.replace('Profile', { owner: 'Michaś' });

push

将新屏幕推送到堆栈顶部并导航到它。该方法接受以下参数:

¥Pushes a new screen to top of the stack and navigate to it. The method accepts following arguments:

  • name - string - 要推入堆栈的路由名称。

    ¥name - string - Name of the route to push onto the stack.

  • params - object - 屏幕参数传递到目标路由。

    ¥params - object - Screen params to pass to the destination route.

navigation.push('Profile', { owner: 'Michaś' });

pop

从堆栈中弹出当前屏幕并导航回上一个屏幕。它需要一个可选参数 (count),它允许你指定要弹出的屏幕数。

¥Pops the current screen from the stack and navigates back to the previous screen. It takes one optional argument (count), which allows you to specify how many screens to pop back by.

navigation.pop();

popToTop

弹出堆栈中除第一个屏幕之外的所有屏幕并导航到它。

¥Pops all of the screens in the stack except the first one and navigates to it.

navigation.popToTop();

示例

¥Example

import { createStackNavigator } from '@react-navigation/stack';

const Stack = createStackNavigator();

function MyStack() {
return (
<Stack.Navigator
initialRouteName="Home"
screenOptions={{
headerMode: 'screen',
headerTintColor: 'white',
headerStyle: { backgroundColor: 'tomato' },
}}
>
<Stack.Screen
name="Home"
component={Home}
options={{
title: 'Awesome app',
}}
/>
<Stack.Screen
name="Profile"
component={Profile}
options={{
title: 'My profile',
}}
/>
<Stack.Screen
name="Settings"
component={Settings}
options={{
gestureEnabled: false,
}}
/>
</Stack.Navigator>
);
}

动画

¥Animations

¥Animation related options

Stack Navigator 提供了各种选项来配置添加或删除屏幕时的过渡动画。通过为每个屏幕指定 options 属性中的选项,可以在每个屏幕上自定义这些过渡动画。

¥Stack Navigator exposes various options to configure the transition animation when a screen is added or removed. These transition animations can be customized on a per-screen basis by specifying the options in the options prop for each screen.

  • gestureDirection - 滑动手势的方向:

    ¥gestureDirection - The direction of swipe gestures:

    • horizontal - 关闭屏幕的手势将从左侧开始,在 RTL 中则从右侧开始。对于动画,SlideFromRightIOS 时屏幕将从右侧滑动,RTL 时屏幕将从左侧滑动。

      ¥horizontal - The gesture to close the screen will start from the left, and from the right in RTL. For animations, screen will slide from the right with SlideFromRightIOS, and from the left in RTL.

    • horizontal-inverted - 关闭屏幕的手势将从右侧开始,在 RTL 中则从左侧开始。对于动画,屏幕将以 SlideFromRightIOS 从左侧滑动,在 RTL 中则从右侧滑动,方向相反。

      ¥horizontal-inverted - The gesture to close the screen will start from the right, and from the left in RTL. For animations, screen will slide from the left with SlideFromRightIOS, and from the right in RTL as the direction is inverted.

    • vertical - 关闭屏幕的手势将从顶部开始。对于动画,屏幕将从底部滑动。

      ¥vertical - The gesture to close the screen will start from the top. For animations, screen will slide from the bottom.

    • vertical-inverted - 关闭屏幕的手势将从底部开始。对于动画,屏幕将从顶部滑动。

      ¥vertical-inverted - The gesture to close the screen will start from the bottom. For animations, screen will slide from the top.

    你可能还想与 gestureDirection 一起指定匹配的水平/垂直动画。对于库中包含的动画,如果将 gestureDirection 设置为反转动画之一,它也会翻转动画方向。

    ¥You may want to specify a matching horizontal/vertical animation along with gestureDirection as well. For the animations included in the library, if you set gestureDirection to one of the inverted ones, it'll also flip the animation direction.

  • transitionSpec - 指定动画类型(timingspring)及其选项(例如 duration 代表 timing)的对象。它需要 2 个属性:

    ¥transitionSpec - An object which specifies the animation type (timing or spring) and their options (such as duration for timing). It takes 2 properties:

    • open - 添加屏幕时的转换配置

      ¥open - Configuration for the transition when adding a screen

    • close - 移除屏幕时的转换配置。

      ¥close - Configuration for the transition when removing a screen.

    每个对象应指定 2 个属性:

    ¥Each of the object should specify 2 properties:

    • animation - 用于动画的动画函数。支持的值为 timingspring

      ¥animation - The animation function to use for the animation. Supported values are timing and spring.

    • config - 定时功能的配置对象。对于 timing,可以是 durationeasing。对于 spring,可以是 stiffnessdampingmassovershootClampingrestDisplacementThresholdrestSpeedThreshold

      ¥config - The configuration object for the timing function. For timing, it can be duration and easing. For spring, it can be stiffness, damping, mass, overshootClamping, restDisplacementThreshold and restSpeedThreshold.

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

    ¥A config which uses spring animation looks like this:

    const config = {
    animation: 'spring',
    config: {
    stiffness: 1000,
    damping: 500,
    mass: 3,
    overshootClamping: true,
    restDisplacementThreshold: 0.01,
    restSpeedThreshold: 0.01,
    },
    };

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

    ¥We can pass this config in the transitionSpec option:

    <Stack.Screen
    name="Profile"
    component={Profile}
    options={{
    transitionSpec: {
    open: config,
    close: config,
    },
    }}
    />
  • cardStyleInterpolator - 这是一个指定卡片各个部分的插值样式的函数。这允许你在从一个屏幕导航到另一个屏幕时自定义转换。预计至少返回空对象,可能包含容器、卡片本身、覆盖和阴影的插值样式。支持的属性有:

    ¥cardStyleInterpolator - This is a function which specifies interpolated styles for various parts of the card. This allows you to customize the transitions when navigating from screen to screen. It is expected to return at least empty object, possibly containing interpolated styles for container, the card itself, overlay and shadow. Supported properties are:

    • containerStyle - 封装卡片的容器视图的样式。

      ¥containerStyle - Style for the container view wrapping the card.

    • cardStyle - 代表卡片的视图的样式。

      ¥cardStyle - Style for the view representing the card.

    • overlayStyle - 代表下面半透明覆盖层的视图的样式

      ¥overlayStyle - Style for the view representing the semi-transparent overlay below

    • shadowStyle - 表示卡片阴影的视图的样式。

      ¥shadowStyle - Style for the view representing the card shadow.

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

    ¥The function receives the following properties in its argument:

    • current - 当前屏幕的值:

      ¥current - Values for the current screen:

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

        ¥progress - Animated node representing the progress value of the current screen.

    • next - 堆栈中这一屏幕之后的屏幕值。如果屏幕动画是最后一个,则可以是 undefined

      ¥next - Values for the screen after this one in the stack. This can be undefined in case the screen animating is the last one.

      • progress - 代表下一屏进度值的动画节点。

        ¥progress - Animated node representing the progress value of the next screen.

    • index - 卡在堆栈中的索引。

      ¥index - The index of the card in the stack.

    • closing - 表示卡片是否正在关闭的动画节点。关闭时为 1,未关闭时为 0

      ¥closing - Animated node representing whether the card is closing. 1 when closing, 0 if not.

    • layouts - 我们用于动画的各种项目的布局测量。

      ¥layouts - Layout measurements for various items we use for animation.

      • screen - 整个屏幕的布局。包含 heightwidth 属性。

        ¥screen - Layout of the whole screen. Contains height and width properties.

    请注意,当某个屏幕不是最后一个屏幕时,它将使用下一个屏幕的转换配置。这是因为许多过渡涉及前一个屏幕的动画,因此这两个过渡需要保持在一起,以防止在两个屏幕上运行两种不同类型的过渡(例如幻灯片和模态)。你可以检查 next 参数来确定是否要为上一屏幕设置动画。有关此参数的更多信息,请参阅 动画 部分。

    ¥Note that when a screen is not the last, it will use the next screen's transition config. This is because many transitions involve an animation of the previous screen, and so these two transitions need to be kept together to prevent running two different kinds of transitions on the two screens (for example a slide and a modal). You can check the next parameter to find out if you want to animate out the previous screen. For more information about this parameter, see Animation section.

    只是淡出屏幕的配置如下所示:

    ¥A config which just fades the screen looks like this:

    const forFade = ({ current }) => ({
    cardStyle: {
    opacity: current.progress,
    },
    });

    我们可以在 cardStyleInterpolator 选项中传递这个函数:

    ¥We can pass this function in cardStyleInterpolator option:

    <Stack.Screen
    name="Profile"
    component={Profile}
    options={{ cardStyleInterpolator: forFade }}
    />

    每个屏幕都会调用插值器。例如,假设堆栈中有 2 个屏幕,A 和 B。B 是进入焦点的新屏幕,A 是上一个屏幕。将为每个屏幕调用插值器:

    ¥The interpolator will be called for each screen. For example, say you have a 2 screens in the stack, A & B. B is the new screen coming into focus and A is the previous screen. The interpolator will be called for each screen:

    • B 调用插值器:这里,current.progress 值代表转换的进度,转换将从 0 开始并在 1 结束。不会有 next.progress,因为 B 是最后一个屏幕。

      ¥The interpolator is called for B: Here, the current.progress value represents the progress of the transition, which will start at 0 and end at 1. There won't be a next.progress since B is the last screen.

    • A 调用插值器:此处,current.progress 将保持 1 的值并且不会更改,因为当前转换是针对 B 而不是 A 运行。next.progress 值代表 B 的进度,将从 0 开始,到 1 结束。

      ¥The interpolator is called for A: Here, the current.progress will stay at the value of 1 and won't change, since the current transition is running for B, not A. The next.progress value represents the progress of B and will start at 0 and end at 1.

    假设我们要在转换期间为两个屏幕设置动画。最简单的方法是将当前屏幕和下一个屏幕的进度值结合起来:

    ¥Say we want to animate both screens during the transition. The easiest way to do it would be to combine the progress value of current and next screens:

    const progress = Animated.add(
    current.progress.interpolate({
    inputRange: [0, 1],
    outputRange: [0, 1],
    extrapolate: 'clamp',
    }),
    next
    ? next.progress.interpolate({
    inputRange: [0, 1],
    outputRange: [0, 1],
    extrapolate: 'clamp',
    })
    : 0
    );

    在这里,屏幕 A 将同时具有 current.progressnext.progress,由于 current.progress 停留在 1,而 next.progress 正在变化,综合起来,进度将从 1 变为 2。屏幕 B 将只有 current.progress,将从 0 变为 1。因此,我们可以对 0-11-2 应用不同的插值来分别为聚焦屏幕和未聚焦屏幕设置动画。

    ¥Here, the screen A will have both current.progress and next.progress, and since current.progress stays at 1 and next.progress is changing, combined, the progress will change from 1 to 2. The screen B will only have current.progress which will change from 0 to 1. So, we can apply different interpolations for 0-1 and 1-2 to animate focused screen and unfocused screen respectively.

    将前一个屏幕稍微向左平移并从右边缘平移当前屏幕的配置如下所示:

    ¥A config which translates the previous screen slightly to the left, and translates the current screen from the right edge would look like this:

    const forSlide = ({ current, next, inverted, layouts: { screen } }) => {
    const progress = Animated.add(
    current.progress.interpolate({
    inputRange: [0, 1],
    outputRange: [0, 1],
    extrapolate: 'clamp',
    }),
    next
    ? next.progress.interpolate({
    inputRange: [0, 1],
    outputRange: [0, 1],
    extrapolate: 'clamp',
    })
    : 0
    );

    return {
    cardStyle: {
    transform: [
    {
    translateX: Animated.multiply(
    progress.interpolate({
    inputRange: [0, 1, 2],
    outputRange: [
    screen.width, // Focused, but offscreen in the beginning
    0, // Fully focused
    screen.width * -0.3, // Fully unfocused
    ],
    extrapolate: 'clamp',
    }),
    inverted
    ),
    },
    ],
    },
    };
    };
  • headerStyleInterpolator - 这是一个为标题的各个部分指定插值样式的函数。预计至少返回空对象,可能包含左标签和按钮、右按钮、标题和背景的插值样式。支持的属性有:

    ¥headerStyleInterpolator - This is a function which specifies interpolated styles for various parts of the header. It is expected to return at least empty object, possibly containing interpolated styles for left label and button, right button, title and background. Supported properties are:

    • leftLabelStyle - 左侧按钮标签的样式(后退按钮标签)。

      ¥leftLabelStyle - Style for the label of the left button (back button label).

    • leftButtonStyle - 左侧按钮(通常是后退按钮)的样式。

      ¥leftButtonStyle - Style for the left button (usually the back button).

    • rightButtonStyle - 右侧按钮的样式。

      ¥rightButtonStyle - Style for the right button.

    • titleStyle - 标题文本的样式。

      ¥titleStyle - Style for the header title text.

    • backgroundStyle - 标题背景的样式。

      ¥backgroundStyle - Style for the header background.

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

    ¥The function receives the following properties in it's argument:

    • current - 当前屏幕(拥有此标题的屏幕)的值。

      ¥current - Values for the current screen (the screen which owns this header).

      • progress - 代表当前屏幕进度值的动画节点。0 表示屏幕应开始进入视野,0.5 表示屏幕处于中间位置,1 表示屏幕应完全呈现在视野中。

        ¥progress - Animated node representing the progress value of the current screen. 0 when screen should start coming into view, 0.5 when it's mid-way, 1 when it should be fully in view.

    • next - 堆栈中这一屏幕之后的屏幕值。如果屏幕动画是最后一个,则可以是 undefined

      ¥next - Values for the screen after this one in the stack. This can be undefined in case the screen animating is the last one.

      • progress - 代表下一屏进度值的动画节点。

        ¥progress - Animated node representing the progress value of the next screen.

    • layouts - 我们用于动画的各种项目的布局测量。每个布局对象都包含 heightwidth 属性。

      ¥layouts - Layout measurements for various items we use for animation. Each layout object contain height and width properties.

      • screen - 整个屏幕的布局。

        ¥screen - Layout of the whole screen.

      • title - 标题元素的布局。不渲染标题时可能是 undefined

        ¥title - Layout of the title element. Might be undefined when not rendering a title.

      • leftLabel - 后退按钮标签的布局。不渲染后退按钮标签时可能是 undefined

        ¥leftLabel - Layout of the back button label. Might be undefined when not rendering a back button label.

    只是淡入淡出元素的配置如下所示:

    ¥A config which just fades the elements looks like this:

    const forFade = ({ current, next }) => {
    const opacity = Animated.add(
    current.progress,
    next ? next.progress : 0
    ).interpolate({
    inputRange: [0, 1, 2],
    outputRange: [0, 1, 0],
    });

    return {
    leftButtonStyle: { opacity },
    rightButtonStyle: { opacity },
    titleStyle: { opacity },
    backgroundStyle: { opacity },
    };
    };

    我们可以在 headerStyleInterpolator 选项中传递这个函数:

    ¥We can pass this function in headerStyleInterpolator option:

    <Stack.Screen
    name="Profile"
    component={Profile}
    options={{ headerStyleInterpolator: forFade }}
    />

预制配置

¥Pre-made configs

使用这些选项,可以为屏幕构建自定义过渡动画。我们还从库中导出各种配置以及你可以使用的现成动画:

¥With these options, it's possible to build custom transition animations for screens. We also export various configs from the library with ready-made animations which you can use:

TransitionSpecs

  • TransitionIOSSpec - 来自 UINavigationController 动画配置的精确值。

    ¥TransitionIOSSpec - Exact values from UINavigationController's animation configuration.

  • FadeInFromBottomAndroidSpec - Android Nougat 活动打开动画的配置。

    ¥FadeInFromBottomAndroidSpec - Configuration for activity open animation from Android Nougat.

  • FadeOutToBottomAndroidSpec - Android Nougat 活动关闭动画的配置。

    ¥FadeOutToBottomAndroidSpec - Configuration for activity close animation from Android Nougat.

  • RevealFromBottomAndroidSpec - Android Pie 中活动打开动画的大致配置。

    ¥RevealFromBottomAndroidSpec - Approximate configuration for activity open animation from Android Pie.

示例:

¥Example:

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

// ...

<Stack.Screen
name="Profile"
component={Profile}
options={{
transitionSpec: {
open: TransitionSpecs.TransitionIOSSpec,
close: TransitionSpecs.TransitionIOSSpec,
},
}}
/>;

CardStyleInterpolators

  • forHorizontalIOS - 标准 iOS 风格从右侧滑入。

    ¥forHorizontalIOS - Standard iOS-style slide in from the right.

  • forVerticalIOS - 标准 iOS 风格从底部滑入(用于模式)。

    ¥forVerticalIOS - Standard iOS-style slide in from the bottom (used for modals).

  • forModalPresentationIOS - iOS 13 中的标准 iOS 风格模态动画。

    ¥forModalPresentationIOS - Standard iOS-style modal animation in iOS 13.

  • forFadeFromBottomAndroid - 对于 Android Oreo,标准 Android 风格从底部淡入。

    ¥forFadeFromBottomAndroid - Standard Android-style fade in from the bottom for Android Oreo.

  • forRevealFromBottomAndroid - Android Pie 的标准 Android 风格从底部显示。

    ¥forRevealFromBottomAndroid - Standard Android-style reveal from the bottom for Android Pie.

Android Oreo 风格竖屏淡入淡出动画配置示例:

¥Example configuration for Android Oreo style vertical screen fade animation:

import { CardStyleInterpolators } from '@react-navigation/stack';

// ...

<Stack.Screen
name="Profile"
component={Profile}
options={{
title: 'Profile',
cardStyleInterpolator: CardStyleInterpolators.forFadeFromBottomAndroid,
}}
/>;

HeaderStyleInterpolators

  • forUIKit - 标准 UIKit 风格的标题动画,其中标题淡入后退按钮标签。

    ¥forUIKit - Standard UIKit style animation for the header where the title fades into the back button label.

  • forFade - 标题元素的简单淡入淡出动画。

    ¥forFade - Simple fade animation for the header elements.

  • forStatic - 简单的翻译动画可随滑动屏幕翻译标题。

    ¥forStatic - Simple translate animation to translate the header along with the sliding screen.

标题元素淡入后退按钮的默认 iOS 动画的示例配置:

¥Example configuration for default iOS animation for header elements where the title fades into the back button:

import { HeaderStyleInterpolators } from '@react-navigation/stack';

// ...

<Stack.Screen
name="Profile"
component={Profile}
options={{
title: 'Profile',
headerStyleInterpolator: HeaderStyleInterpolators.forUIKit,
}}
/>;
警告

始终在文件的顶层定义动画配置,以确保引用不会在重新渲染时发生更改。这对于平滑可靠的过渡动画非常重要。

¥Always define your animation configuration at the top-level of the file to ensure that the references don't change across re-renders. This is important for smooth and reliable transition animations.

TransitionPresets

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

¥We export various transition presets which bundle various set of these options together to match certain native animations. A transition preset is an object containing few animation related screen options exported under TransitionPresets. Currently the following presets are available:

  • SlideFromRightIOS - 标准 iOS 导航转换。

    ¥SlideFromRightIOS - Standard iOS navigation transition.

  • ModalSlideFromBottomIOS - 模式的标准 iOS 导航转换。

    ¥ModalSlideFromBottomIOS - Standard iOS navigation transition for modals.

  • ModalPresentationIOS - 标准 iOS 模式呈现样式(在 iOS 13 中引入)。

    ¥ModalPresentationIOS - Standard iOS modal presentation style (introduced in iOS 13).

  • FadeFromBottomAndroid - 在 Android < 9 (Oreo) 上打开或关闭活动时的标准 Android 导航转换。

    ¥FadeFromBottomAndroid - Standard Android navigation transition when opening or closing an Activity on Android < 9 (Oreo).

  • RevealFromBottomAndroid - 在 Android 9 (Pie) 上打开或关闭 Activity 时的标准 Android 导航转换。

    ¥RevealFromBottomAndroid - Standard Android navigation transition when opening or closing an Activity on Android 9 (Pie).

  • ScaleFromCenterAndroid - 在 Android >= 10 上打开或关闭 Activity 时的标准 Android 导航转换。

    ¥ScaleFromCenterAndroid - Standard Android navigation transition when opening or closing an Activity on Android >= 10.

  • DefaultTransition - 当前平台的默认导航转换。

    ¥DefaultTransition - Default navigation transition for the current platform.

  • ModalTransition - 当前平台的默认模式转换。

    ¥ModalTransition - Default modal transition for the current platform.

你可以在 options 中传播这些预设来自定义屏幕动画:

¥You can spread these presets in options to customize the animation for a screen:

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

// ...

<Stack.Screen
name="Profile"
component={Profile}
options={{
title: 'Profile',
...TransitionPresets.ModalSlideFromBottomIOS,
}}
/>;

如果要为导航器中的所有屏幕自定义过渡动画,可以在导航器的 screenOptions 属性中指定。

¥If you want to customize the transition animations for all of the screens in the navigator, you can specify it in screenOptions prop for the navigator.

iOS 模态呈现样式的示例配置:

¥Example configuration for iOS modal presentation style:

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

// ...

<Stack.Navigator
initialRouteName="Home"
screenOptions={({ route, navigation }) => ({
headerShown: false,
gestureEnabled: true,
...TransitionPresets.ModalPresentationIOS,
})}
>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Profile" component={Profile} />
</Stack.Navigator>;

透明模态框

¥Transparent modals

透明模式就像覆盖屏幕的模式对话框。之前的屏幕在下面仍然可见。要获得透明模态屏幕,你可以在屏幕选项中指定 presentation: 'transparentModal'

¥A transparent modal is like a modal dialog which overlays the screen. The previous screen still stays visible underneath. To get a transparent modal screen, you can specify presentation: 'transparentModal' in the screen's options.

示例:

¥Example:

<Stack.Navigator>
<Stack.Screen name="Home" component={HomeStack} />
<Stack.Screen
name="Modal"
component={ModalScreen}
options={{ presentation: 'transparentModal' }}
/>
</Stack.Navigator>

现在,当你导航到 Modal 屏幕时,它将具有透明背景,并且 Home 屏幕将在下面可见。

¥Now, when you navigate to the Modal screen, it'll have a transparent background and the Home screen will be visible underneath.

除了 presentation 之外,你可能还需要选择指定更多内容来获得类似行为的模式对话框:

¥In addition to presentation, you might want to optionally specify few more things to get a modal dialog like behavior:

  • 使用 headerShown: false 禁用标头

    ¥Disable the header with headerShown: false

  • 使用 cardOverlayEnabled: true 启用覆盖层(你无法通过这种方式点击覆盖层来关闭屏幕,请参阅下面的替代方案)

    ¥Enable the overlay with cardOverlayEnabled: true (you can't tap the overlay to close the screen this way, see below for alternatives)

如果你想进一步自定义对话框的动画方式,或者想在点击覆盖层等时关闭屏幕,你可以使用 useCardAnimation 钩子来自定义屏幕内的元素。

¥If you want to further customize how the dialog animates, or want to close the screen when tapping the overlay etc., you can use the useCardAnimation hook to customize elements inside your screen.

示例:

¥Example:

import {
Animated,
View,
Text,
Pressable,
Button,
StyleSheet,
} from 'react-native';
import { useTheme } from '@react-navigation/native';
import { useCardAnimation } from '@react-navigation/stack';

function ModalScreen({ navigation }) {
const { colors } = useTheme();
const { current } = useCardAnimation();

return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}
>
<Pressable
style={[
StyleSheet.absoluteFill,
{ backgroundColor: 'rgba(0, 0, 0, 0.5)' },
]}
onPress={navigation.goBack}
/>
<Animated.View
style={{
padding: 16,
width: '90%',
maxWidth: 400,
borderRadius: 3,
backgroundColor: colors.card,
transform: [
{
scale: current.progress.interpolate({
inputRange: [0, 1],
outputRange: [0.9, 1],
extrapolate: 'clamp',
}),
},
],
}}
>
<Text>
Mise en place is a French term that literally means “put in place. It
also refers to a way cooks in professional kitchens and restaurants
set up their work stations—first by gathering all ingredients for a
recipes, partially preparing them (like measuring out and chopping),
and setting them all near each other. Setting up mise en place before
cooking is another top tip for home cooks, as it seriously helps with
organization. It’ll pretty much guarantee you never forget to add an
ingredient and save you time from running back and forth from the
pantry ten times.
</Text>
<Button
title="Okay"
color={colors.primary}
style={{ alignSelf: 'flex-end' }}
onPress={navigation.goBack}
/>
</Animated.View>
</View>
);
}

在这里,我们对对话框的比例进行动画处理,并添加一个覆盖层来关闭对话框。

¥Here we animate the scale of the dialog, and also add an overlay to close the dialog.