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

抽屉导航器

抽屉导航器在屏幕侧边渲染一个导航抽屉,可以通过手势打开和关闭。

这层封装了 react-native-drawer-layout。 如果您想在没有 React Navigation 集成的情况下使用抽屉,请直接使用该库。

安装

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

npm install @react-navigation/drawer

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

  1. 首先,安装 react-native-gesture-handlerreact-native-reanimated (至少版本 2 或 3)。

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

    npx expo install react-native-gesture-handler react-native-reanimated

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

    npm install react-native-gesture-handler react-native-reanimated
  2. 按照 安装指南 在您的项目中配置 Reanimated Babel 插件。

  3. 为了完成 react-native-gesture-handler 的安装,我们需要有条件地导入它。 为此,创建 2 个文件

    gesture-handler.native.js
    // Only import react-native-gesture-handler on native platforms
    import 'react-native-gesture-handler';
    gesture-handler.js
    // Don't import react-native-gesture-handler on web

    现在,将以下代码添加到您的入口文件的 顶部 (确保它在顶部,并且前面没有任何其他内容),例如 index.jsApp.js

    import './gesture-handler';

    由于抽屉导航器在 Web 上不使用 react-native-gesture-handler,这避免了不必要地增加包大小。

    警告

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

  4. 如果您在 Mac 上为 iOS 开发,您还需要安装 pod (通过 Cocoapods) 以完成链接。

    npx pod-install ios

用法

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

import { createDrawerNavigator } from '@react-navigation/drawer';

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

API 定义

属性

除了所有导航器共享的 通用属性 之外,抽屉导航器组件还接受以下附加属性

backBehavior

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

它支持以下值

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

defaultStatus

抽屉的默认状态 - 抽屉默认应保持 open 还是 closed

当设置为 open 时,抽屉将在初始渲染时打开。 可以使用手势或以编程方式正常关闭。 但是,当返回时,如果抽屉已关闭,则会重新打开。 这本质上与抽屉的默认行为相反,默认行为是抽屉开始时是 closed,并且返回按钮会关闭打开的抽屉。

detachInactiveScreens

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

drawerContent

返回 React 元素的函数,用于渲染为抽屉的内容,例如导航项

内容组件默认接收以下属性

  • state - 导航器的 导航状态
  • navigation - 导航器的导航对象。
  • descriptors - 一个描述符对象,其中包含抽屉屏幕的选项。 可以在 descriptors[route.key].options 访问这些选项。
提供自定义的 drawerContent

抽屉的默认组件是可滚动的,并且仅包含 RouteConfig 中路由的链接。 您可以轻松覆盖默认组件,以向抽屉添加页眉、页脚或其他内容。 默认内容组件导出为 DrawerContent。 它在 ScrollView 内渲染 DrawerItemList 组件。

默认情况下,抽屉是可滚动的,并支持带有凹槽的设备。 如果您自定义内容,可以使用 DrawerContentScrollView 自动处理此问题

import {
DrawerContentScrollView,
DrawerItemList,
} from '@react-navigation/drawer';

function CustomDrawerContent(props) {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
</DrawerContentScrollView>
);
}

要在抽屉中添加其他项目,可以使用 DrawerItem 组件

function CustomDrawerContent(props) {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem
label="Help"
onPress={() => Linking.openURL('https://mywebsite.com/help')}
/>
</DrawerContentScrollView>
);
}

DrawerItem 组件接受以下属性

  • label (必需): 项目的标签文本。 可以是字符串,也可以是返回 React 元素的函数。 例如 ({ focused, color }) => <Text style={{ color }}>{focused ? 'Focused text' : 'Unfocused text'}</Text>
  • icon: 要为项目显示的图标。 接受返回 React 元素的函数。 例如 ({ focused, color, size }) => <Icon color={color} size={size} name={focused ? 'heart' : 'heart-outline'} />
  • focused: 布尔值,指示是否将抽屉项目突出显示为活动状态。
  • onPress (必需): 按下时执行的函数。
  • activeTintColor: 项目处于活动状态时图标和标签的颜色。
  • inactiveTintColor: 项目处于非活动状态时图标和标签的颜色。
  • activeBackgroundColor: 项目处于活动状态时的背景颜色。
  • inactiveBackgroundColor: 项目处于非活动状态时的背景颜色。
  • labelStyle: 标签 Text 的样式对象。
  • style: 包装器 View 的样式对象。

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

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

要使用自定义组件,我们需要在 drawerContent 属性中传递它

<Drawer.Navigator drawerContent={(props) => <CustomDrawerContent {...props} />}>
{/* screens */}
</Drawer.Navigator>

选项

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

title

一个通用标题,可以用作 headerTitledrawerLabel 的后备。

lazy

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

drawerLabel

字符串或一个函数,给定 { focused: boolean, color: string } 返回一个 React.Node,以在抽屉侧边栏中显示。 未定义时,使用场景 title

drawerIcon

函数,给定 { focused: boolean, color: string, size: number } 返回一个 React.Node 以在抽屉侧边栏中显示。

drawerActiveTintColor

抽屉中活动项目的图标和标签的颜色。

Drawer active tint color
   drawerActiveTintColor: 'green',

drawerActiveBackgroundColor

抽屉中活动项目的背景颜色。

Drawer active background color
    screenOptions={{
drawerActiveTintColor: 'white',
drawerActiveBackgroundColor: '#003CB3',
drawerLabelStyle: {
color: 'white',
},
}}

drawerInactiveTintColor

抽屉中非活动项目的图标和标签的颜色。

drawerInactiveBackgroundColor

抽屉中非活动项目的背景颜色。

drawerItemStyle

单个项目的样式对象,可以包含图标和/或标签。

Drawer item style

示例

   drawerItemStyle: {
backgroundColor: '#9dd3c8',
borderColor: 'black',
orderWidth: 2,
opacity: 0.6,
},

drawerLabelStyle

应用于内容部分内部 Text 样式的样式对象,该样式对象渲染标签。

Drawer label style

示例

   drawerLabelStyle: {
color: 'black',
fontSize: 20,
fontFamily: 'Georgia',
},

drawerContentContainerStyle

ScrollView 内部内容部分的样式对象。

drawerContentStyle

包装器视图的样式对象。

drawerStyle

抽屉组件的样式对象。 您可以在此处传递抽屉的自定义背景颜色或自定义宽度。

Drawer style
<Drawer.Navigator
screenOptions={{
drawerStyle: {
backgroundColor: '#c6cbef',
width: 240,
},
}}
>
{/* screens */}
</Drawer.Navigator>

drawerPosition

选项为 leftright。 对于 LTR 语言,默认为 left,对于 RTL 语言,默认为 right

drawerType

抽屉的类型。 它决定了抽屉的外观和动画效果。

  • front: 传统抽屉,用覆盖层覆盖屏幕。

  • back: 在滑动时,抽屉在屏幕后面显示。

  • slide: 在滑动时,屏幕和抽屉都滑动以显示抽屉。

  • permanent: 永久抽屉显示为侧边栏。 适用于在较大屏幕上始终显示抽屉。

在 iOS 上默认为 slide,在其他平台上默认为 front

您可以有条件地指定 drawerType 以在较大屏幕上显示永久抽屉,在较小屏幕上显示传统抽屉

import { useWindowDimensions } from 'react-native';
import { createDrawerNavigator } from '@react-navigation/drawer';

const Drawer = createDrawerNavigator();

function MyDrawer() {
const dimensions = useWindowDimensions();

return (
<Drawer.Navigator
screenOptions={{
drawerType: dimensions.width >= 768 ? 'permanent' : 'front',
}}
>
{/* Screens */}
</Drawer.Navigator>
);
}

您还可以根据屏幕大小指定其他属性,例如 drawerStyle,以自定义行为。 例如,您可以将其与 defaultStatus="open" 结合使用以实现主-详细信息布局

import { useWindowDimensions } from 'react-native';
import { createDrawerNavigator } from '@react-navigation/drawer';

const Drawer = createDrawerNavigator();

function MyDrawer() {
const dimensions = useWindowDimensions();

const isLargeScreen = dimensions.width >= 768;

return (
<Drawer.Navigator
defaultStatus="open"
screenOptions={{
drawerType: isLargeScreen ? 'permanent' : 'back',
drawerStyle: isLargeScreen ? null : { width: '100%' },
overlayColor: 'transparent',
}}
>
{/* Screens */}
</Drawer.Navigator>
);
}

drawerHideStatusBarOnOpen

当设置为 true 时,每当拉出抽屉或抽屉处于“打开”状态时,抽屉都会隐藏 OS 状态栏。

drawerStatusBarAnimation

隐藏状态栏时的状态栏动画。 与 drawerHideStatusBarOnOpen 结合使用。

这仅在 iOS 上受支持。 默认为 slide

支持的值

  • slide

  • fade

  • none

overlayColor

当抽屉打开时,显示在内容视图顶部的颜色覆盖层。 当抽屉打开时,不透明度从 0 动画到 1

sceneStyle

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

configureGestureHandler

用于配置底层 来自 react-native-gesture-handler 的手势 的回调。 它接收 gesture 对象作为参数

configureGestureHandler: ({ gesture }) => {
return gesture.enableTrackpadTwoFingerGesture(false);
},

Web 上不支持此功能。

swipeEnabled

是否可以使用滑动姿势打开或关闭抽屉。 默认为 true

Web 上不支持滑动姿势。

swipeEdgeWidth

允许定义滑动姿势应在距内容视图边缘多远的位置激活。

Web 上不支持此功能。

swipeMinDistance

应激活打开抽屉的最小滑动距离阈值。

keyboardDismissMode

滑动姿势开始时是否应关闭键盘。 默认为 'on-drag'。 设置为 'none' 以禁用键盘处理。

freezeOnBlur

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

仅在 iOS 和 Android 上受支持。

popToTopOnBlur

布尔值,指示当从此抽屉屏幕导航离开时,是否应将任何嵌套堆栈弹出到堆栈顶部。 默认为 false

仅当抽屉导航器下嵌套了堆栈导航器 (例如 堆栈导航器原生堆栈导航器) 时,它才有效。

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

除了这些之外,抽屉还支持以下选项

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

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

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

示例

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

// ..

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

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

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

headerStyle 中指定 height

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

示例

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

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

headerShown

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

事件

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

drawerItemPress

当用户按下抽屉中屏幕的按钮时,将触发此事件。 默认情况下,抽屉项目按下会执行以下几项操作

  • 如果屏幕未聚焦,抽屉项目按下将聚焦该屏幕
  • 如果屏幕已聚焦,则它将关闭抽屉

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

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

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

return unsubscribe;
}, [navigation]);

如果您有自定义抽屉内容,请确保发出此事件。

辅助方法

抽屉导航器向导航对象添加以下方法

openDrawer

打开抽屉窗格。

navigation.openDrawer();

closeDrawer

关闭抽屉窗格。

navigation.closeDrawer();

toggleDrawer

如果抽屉窗格关闭,则打开它;如果抽屉窗格打开,则关闭它。

navigation.toggleDrawer();

jumpTo

导航到抽屉导航器中已存在的屏幕。 该方法接受以下参数

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

钩子

抽屉导航器导出以下钩子

useDrawerProgress

此钩子返回抽屉的进度。 它在抽屉导航器渲染的屏幕组件以及 自定义抽屉内容 中可用。

progress 对象是一个 SharedValue,表示抽屉的动画位置 (0 为关闭; 1 为打开)。 它可用于使用 Reanimated 基于抽屉的动画对元素进行动画处理

import {
createDrawerNavigator,
useDrawerProgress,
} from '@react-navigation/drawer';
import Animated, { useAnimatedStyle } from 'react-native-reanimated';

function HomeScreen() {
const progress = useDrawerProgress();

const animatedStyle = useAnimatedStyle(() => ({
transform: [{ translateX: progress.value * -100 }],
}));

return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Animated.View
style={[
{
height: 100,
aspectRatio: 1,
backgroundColor: 'tomato',
},
animatedStyle,
]}
/>
</View>
);
}
Snack 上尝试

如果您正在使用类组件,则可以使用 DrawerProgressContext 获取进度值。

警告

由于 Web 上未使用 Reanimated,因此 useDrawerProgress 钩子 (或 DrawerProgressContext) 将在 Web 上返回一个模拟值。 模拟值只能表示抽屉的打开状态 (0 表示关闭,1 表示打开),而不能表示抽屉的进度。

useDrawerStatus

您可以使用 useDrawerStatus 钩子检查抽屉是否打开。

import { useDrawerStatus } from '@react-navigation/drawer';

// ...

const isDrawerOpen = useDrawerStatus() === 'open';

如果您不能使用钩子,您还可以使用 getDrawerStatusFromState 辅助方法

import { getDrawerStatusFromState } from '@react-navigation/drawer';

// ...

const isDrawerOpen = getDrawerStatusFromState(navigation.getState()) === 'open';

对于类组件,您可以监听 state 事件以检查抽屉是否已打开或关闭

class Profile extends React.Component {
componentDidMount() {
this._unsubscribe = navigation.addListener('state', () => {
const isDrawerOpen =
getDrawerStatusFromState(navigation.getState()) === 'open';

// do something
});
}

componentWillUnmount() {
this._unsubscribe();
}

render() {
// Content of the component
}
}

在其他导航器内部嵌套抽屉导航器

如果抽屉导航器嵌套在另一个提供某些 UI 的导航器中,例如选项卡导航器或堆栈导航器,则抽屉将在这些导航器的 UI 下方呈现。 抽屉将出现在选项卡栏下方和堆栈的标题下方。 您需要使抽屉导航器成为任何导航器的父级,其中抽屉应在其 UI 之上呈现。