跳至主要内容
版本: 6.x

堆栈导航器

堆栈导航器提供了一种方法,让您的应用程序在屏幕之间进行过渡,其中每个新屏幕都放置在堆栈的顶部。

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

需要注意的是,虽然@react-navigation/stack 非常可定制,但它是在 JavaScript 中实现的。虽然它使用原生方式运行动画和手势,但性能可能不如原生实现快。对于许多应用程序来说,这可能不是问题,但如果您在导航期间遇到性能问题,请考虑使用@react-navigation/native-stack - 它使用原生导航原语。

安装

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

npm install @react-navigation/stack

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

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

    如果您有一个 Expo 管理的项目,在您的项目目录中,运行

    npx expo install react-native-gesture-handler

    如果您有一个裸 React Native 项目,在您的项目目录中,运行

    npm install react-native-gesture-handler
  2. 为了完成 react-native-gesture-handler 的安装,请将以下代码添加到您的入口文件(例如 index.jsApp.js)的 **顶部**(确保它位于顶部,前面没有任何其他代码)。

    import 'react-native-gesture-handler';
    警告

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

  3. 可选地,您也可以安装 @react-native-masked-view/masked-view。如果您想为标题使用 UIKit 风格的动画(HeaderStyleInterpolators.forUIKit),则需要此库。

    如果您有一个 Expo 管理的项目,在您的项目目录中,运行

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

    如果您有一个裸 React Native 项目,在您的项目目录中,运行

    npm install @react-native-masked-view/masked-view
  4. 如果您使用的是 Mac 并为 iOS 开发,您还需要安装 pod(通过 Cocoapods)来完成链接。

npx pod-install ios

API 定义

要使用此导航器,请从 @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>
);
}

属性

Stack.Navigator 组件接受以下属性

id

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

initialRouteName

在导航器首次加载时要渲染的路由的名称。

screenOptions

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

detachInactiveScreens

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

如果您需要为特定屏幕禁用此优化(例如,您希望屏幕即使在失去焦点时也保持在视图中),请使用 detachPreviousScreen 选项。

选项

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

title

可作为headerTitle的备用字符串。

cardShadowEnabled

使用此属性在过渡期间显示可见阴影。默认值为true

cardOverlayEnabled

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

cardOverlay

返回 React 元素的函数,该元素将作为卡片的覆盖层显示。使用此属性时,请确保将cardOverlayEnabled设置为true

cardStyle

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

您还可以指定{ backgroundColor: 'transparent' },使之前的屏幕在下方可见(用于透明模态)。这对于实现模态对话框等功能很有用。使用透明背景时,您还应在选项中指定presentation: 'modal',以便之前的屏幕不会分离并保持在下方可见。

在 Web 上,屏幕的高度不受视窗高度的限制。这是为了允许浏览器地址栏在滚动时隐藏。如果这不是期望的行为,您可以将cardStyle设置为{ flex: 1 },以强制屏幕填充视窗。

presentation

这是一个快捷选项,用于配置多个选项来配置渲染和过渡的样式。

  • card: 使用 iOS 和 Android 屏幕过渡的默认操作系统动画。
  • modal: 使用模态动画。这会改变一些东西
    • 除非另有说明,否则将屏幕的 headerMode 设置为 screen
    • 更改屏幕动画以匹配模态的平台行为。
  • transparentModal: 与 modal 类似。这会改变以下内容
    • 除非另有说明,否则将屏幕的 headerMode 设置为 screen
    • 将屏幕的背景颜色设置为透明,以便显示上一个屏幕
    • 调整 detachPreviousScreen 选项,以便上一个屏幕保持渲染。
    • 防止上一个屏幕从其最后位置进行动画。
    • 将屏幕动画更改为垂直滑动动画。

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

animationEnabled

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

animationTypeForReplace

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

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

默认为 push

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

gestureEnabled

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

Web 上不支持手势。

gestureResponseDistance

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

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

默认值是

  • 50 - 当 gestureDirectionhorizontalhorizontal-inverted
  • 135 - 当 gestureDirectionverticalvertical-inverted

这在 Web 上不受支持。

gestureVelocityImpact

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

这在 Web 上不受支持。

gestureDirection

手势的方向。有关详细信息,请参阅 动画部分

这在 Web 上不受支持。

transitionSpec

屏幕过渡的配置对象。有关详细信息,请参阅 动画部分

cardStyleInterpolator

卡片各个部分的插值样式。有关详细信息,请参阅 动画部分

headerStyleInterpolator

标题各个部分的插值样式。有关详细信息,请参阅 动画部分

keyboardHandlingEnabled

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

detachPreviousScreen

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

当使用 presentation 作为 transparentModalmodal 时,此值会自动调整,以确保必要的屏幕可见。在其他情况下,默认值为 true

freezeOnBlur

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

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

仅在 iOS 和 Android 上支持。

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

除了这些选项之外,堆栈还支持以下选项

自定义标题,用于代替默认标题。

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

  • navigation - 当前屏幕的导航对象。
  • route - 当前屏幕的路由对象。
  • options - 当前屏幕的选项
  • layout - 屏幕的尺寸,包含 heightwidth 属性。
  • progress 表示动画进度的动画节点。
  • back - 返回按钮的选项,包含一个具有 title 属性的对象,用于返回按钮标签。
  • styleInterpolator - 返回标题中各种元素的插值样式的函数。

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

示例

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 属性中指定此选项。

使用自定义标题时,需要注意两点

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

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

示例

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

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

headerMode设置为float以进行自定义标题动画

默认情况下,有一个浮动标题,它在 iOS 上为非模态渲染多个屏幕的标题。这些标题包括动画,以平滑地切换到彼此。

如果您指定自定义标题,React Navigation 将自动将其更改为screen,以便标题与屏幕一起动画。这意味着您不必实现动画来单独对其进行动画处理。

但是您可能希望保留浮动标题以在标题之间具有不同的过渡动画。为此,您需要在选项中指定headerMode: 'float',然后在自定义标题中的progress.currentprogress.next道具上进行插值。例如,以下将交叉淡化标题

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

指定标题的渲染方式

  • float - 渲染一个始终位于顶部并在更改屏幕时进行动画处理的单个标题。这是 iOS 上的默认设置。
  • screen - 每个屏幕都附带一个标题,并且标题与屏幕一起淡入淡出。这是其他平台上的默认设置。

headerShown

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

headerBackAllowFontScaling

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

headerBackAccessibilityLabel

头部返回按钮的无障碍标签。

headerBackImage

返回一个 React 元素,用于在头部返回按钮中显示自定义图像的函数。当使用函数时,它会在其参数对象中接收 tintColor。默认情况下,使用带有返回图像源的 Image 组件,该源是平台的默认返回图标图像(iOS 上为 Chevron,Android 上为箭头)。

headerBackTitle

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

headerBackTitleVisible

对于是否应该显示返回按钮标题,提供了一个合理的默认值,但如果您想覆盖它,可以在此选项中使用 truefalse

headerTruncatedBackTitle

headerBackTitle 不适合屏幕时,返回按钮使用的标题字符串。默认情况下为 "Back"

headerBackTitleStyle

返回标题的样式对象。

事件

导航器可以在某些操作时 发出事件。支持的事件有

transitionStart

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

事件数据

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

示例

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

return unsubscribe;
}, [navigation]);

transitionEnd

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

事件数据

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

示例

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

return unsubscribe;
}, [navigation]);

gestureStart

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

示例

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

return unsubscribe;
}, [navigation]);

gestureEnd

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

示例

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

return unsubscribe;
}, [navigation]);

gestureCancel

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

示例

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

return unsubscribe;
}, [navigation]);

辅助方法

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

replace

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

  • name - string - 要推送到堆栈的路由名称。
  • params - object - 传递到目标路由的屏幕参数。
navigation.replace('Profile', { owner: 'Michaś' });

push

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

  • name - string - 要推送到堆栈的路由名称。
  • params - object - 传递到目标路由的屏幕参数。
navigation.push('Profile', { owner: 'Michaś' });

pop

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

navigation.pop();

popToTop

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

navigation.popToTop();

示例

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>
);
}

动画

堆栈导航器公开了各种选项来配置添加或删除屏幕时的过渡动画。这些过渡动画可以通过在每个屏幕的options属性中指定选项来在每个屏幕的基础上进行自定义。

  • gestureDirection - 滑动手势的方向

    • horizontal - 关闭屏幕的手势将从左侧开始,在 RTL 中从右侧开始。对于动画,屏幕将使用SlideFromRightIOS从右侧滑动,在 RTL 中从左侧滑动。
    • horizontal-inverted - 关闭屏幕的手势将从右侧开始,在 RTL 中从左侧开始。对于动画,屏幕将使用SlideFromRightIOS从左侧滑动,在 RTL 中从右侧滑动,因为方向被反转。
    • vertical - 关闭屏幕的手势将从顶部开始。对于动画,屏幕将从底部滑动。
    • vertical-inverted - 关闭屏幕的手势将从底部开始。对于动画,屏幕将从顶部滑动。

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

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

    • open - 添加屏幕时过渡的配置
    • close - 删除屏幕时过渡的配置。

    每个对象都应该指定 2 个属性

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

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

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

    我们可以将此配置传递给transitionSpec 选项

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

    • containerStyle - 包裹卡片的容器视图的样式。
    • cardStyle - 表示卡片的视图的样式。
    • overlayStyle - 表示下方半透明覆盖层的视图的样式
    • shadowStyle - 表示卡片阴影的视图的样式。

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

    • current - 当前屏幕的值
      • progress - 表示当前屏幕进度值的动画节点。
    • next - 堆栈中下一个屏幕的值。如果正在动画的屏幕是最后一个屏幕,则它可以是undefined
      • progress - 表示下一个屏幕进度值的动画节点。
    • index - 堆栈中卡片的索引。
    • closing - 表示卡片是否正在关闭的动画节点。关闭时为1,否则为0
    • layouts - 我们用于动画的各种项目的布局测量值。
      • screen - 整个屏幕的布局。包含heightwidth 属性。

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

    一个只淡出屏幕的配置如下所示

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

    我们可以将此函数传递给 cardStyleInterpolator 选项

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

    插值器将针对每个屏幕调用。例如,假设您在堆栈中拥有 2 个屏幕,A 和 B。B 是即将进入焦点的屏幕,A 是前一个屏幕。插值器将针对每个屏幕调用

    • 插值器针对 B 调用:在这里,current.progress 值表示过渡的进度,它将从 0 开始,到 1 结束。不会有 next.progress,因为 B 是最后一个屏幕。
    • 插值器针对 A 调用:在这里,current.progress 将保持在 1 的值,并且不会改变,因为当前过渡针对的是 B,而不是 Anext.progress 值表示 B 的进度,它将从 0 开始,到 1 结束。

    假设我们想要在过渡期间对两个屏幕都进行动画处理。最简单的方法是将当前屏幕和下一个屏幕的进度值组合起来

    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 应用不同的插值,分别对聚焦屏幕和非聚焦屏幕进行动画处理。

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

    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 - 这是一个函数,它指定了标题各个部分的插值样式。它应该至少返回一个空对象,可能包含左侧标签和按钮、右侧按钮、标题和背景的插值样式。支持的属性是

    • leftLabelStyle - 左侧按钮(返回按钮标签)的样式。
    • leftButtonStyle - 左侧按钮(通常是返回按钮)的样式。
    • rightButtonStyle - 右侧按钮的样式。
    • titleStyle - 标题文本的样式。
    • backgroundStyle - 标题背景的样式。

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

    • current - 当前屏幕(拥有此标题的屏幕)的值。
      • progress - 表示当前屏幕进度值的动画节点。0 表示屏幕开始进入视图,0.5 表示屏幕处于中间位置,1 表示屏幕应该完全进入视图。
    • next - 堆栈中下一个屏幕的值。如果正在动画的屏幕是最后一个屏幕,则它可以是undefined
      • progress - 表示下一个屏幕进度值的动画节点。
    • layouts - 用于动画的各种项目的布局测量值。每个布局对象包含heightwidth 属性。
      • screen - 整个屏幕的布局。
      • title - 标题元素的布局。当不渲染标题时,可能为undefined
      • leftLabel - 返回按钮标签的布局。当不渲染返回按钮标签时,可能为undefined

    一个只淡出元素的配置看起来像这样

    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 选项

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

预制配置

使用这些选项,可以为屏幕构建自定义过渡动画。我们还从库中导出各种配置,其中包含可以使用的预制动画

TransitionSpecs

  • TransitionIOSSpec - 来自 UINavigationController 动画配置的精确值。
  • FadeInFromBottomAndroidSpec - Android Nougat 中活动打开动画的配置。
  • FadeOutToBottomAndroidSpec - Android Nougat 中活动关闭动画的配置。
  • RevealFromBottomAndroidSpec - Android Pie 中活动打开动画的大致配置。

示例

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

// ...

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

CardStyleInterpolators

  • forHorizontalIOS - 标准 iOS 风格的从右侧滑入动画。
  • forVerticalIOS - 标准 iOS 风格的从底部滑入动画(用于模态视图)。
  • forModalPresentationIOS - iOS 13 中标准的 iOS 风格模态动画。
  • forFadeFromBottomAndroid - 标准 Android 风格的从底部淡入动画,适用于 Android Oreo。
  • forRevealFromBottomAndroid - 标准 Android 风格的从底部揭示动画,适用于 Android Pie。

Android Oreo 风格的垂直屏幕淡入动画示例配置

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

// ...

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

HeaderStyleInterpolators

  • forUIKit - 标准 UIKit 风格的标题动画,标题会淡入后退按钮标签。
  • forFade - 标题元素的简单淡入动画。
  • forStatic - 简单的平移动画,将标题与滑动屏幕一起平移。

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

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

// ...

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

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

TransitionPresets

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

  • SlideFromRightIOS - 标准 iOS 导航过渡。
  • ModalSlideFromBottomIOS - 模态视图的标准 iOS 导航过渡。
  • ModalPresentationIOS - 标准 iOS 模态呈现样式(在 iOS 13 中引入)。
  • FadeFromBottomAndroid - Android < 9(Oreo)上打开或关闭 Activity 时的标准 Android 导航过渡。
  • RevealFromBottomAndroid - Android 9(Pie)上打开或关闭 Activity 时的标准 Android 导航过渡。
  • ScaleFromCenterAndroid - Android >= 10 上打开或关闭 Activity 时的标准 Android 导航过渡。
  • DefaultTransition - 当前平台的默认导航过渡。
  • ModalTransition - 当前平台的默认模态过渡。

您可以将这些预设值扩展到 options 中,以自定义屏幕的动画。

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

// ...

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

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

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

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>;

透明模态

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

示例

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

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

除了 presentation 之外,您可能还想选择指定一些其他内容以获得类似模态对话框的行为

  • 使用 headerShown: false 禁用标题
  • 使用 cardOverlayEnabled: true 启用叠加层(您无法通过这种方式点击叠加层来关闭屏幕,请参阅下面的替代方法)

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

示例

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>
);
}

这里我们动画了对话框的缩放,并添加了一个叠加层来关闭对话框。