抽屉导航器
抽屉导航器在屏幕侧边渲染一个导航抽屉,可以通过手势打开和关闭。
这层封装了 react-native-drawer-layout
。 如果您想在没有 React Navigation 集成的情况下使用抽屉,请直接使用该库。
安装
要使用此导航器,请确保您已安装 @react-navigation/native
及其依赖项 (请遵循本指南),然后安装 @react-navigation/drawer
- npm
- Yarn
- pnpm
npm install @react-navigation/drawer
yarn add @react-navigation/drawer
pnpm add @react-navigation/drawer
然后,您需要安装和配置抽屉导航器所需的库
-
首先,安装
react-native-gesture-handler
和react-native-reanimated
(至少版本 2 或 3)。如果您有一个 Expo 管理的项目,请在您的项目目录中运行
npx expo install react-native-gesture-handler react-native-reanimated
如果您有一个裸 React Native 项目,请在您的项目目录中运行
- npm
- Yarn
- pnpm
npm install react-native-gesture-handler react-native-reanimated
yarn add react-native-gesture-handler react-native-reanimated
pnpm add react-native-gesture-handler react-native-reanimated
-
按照 安装指南 在您的项目中配置 Reanimated Babel 插件。
-
为了完成
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.js
或App.js
import './gesture-handler';
由于抽屉导航器在 Web 上不使用
react-native-gesture-handler
,这避免了不必要地增加包大小。警告如果您正在为 Android 或 iOS 构建,请不要跳过此步骤,否则您的应用可能在生产环境中崩溃,即使它在开发环境中运行良好。 这不适用于其他平台。
-
如果您在 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,
},
});
import { createDrawerNavigator } from '@react-navigation/drawer';
const Drawer = createDrawerNavigator();
function MyDrawer() {
return (
<Drawer.Navigator>
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Profile" component={ProfileScreen} />
</Drawer.Navigator>
);
}
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.navigator
的 screenOptions
属性或 Drawer.Screen
的 options
属性下指定。
title
一个通用标题,可以用作 headerTitle
和 drawerLabel
的后备。
lazy
此屏幕是否应在首次访问时渲染。 默认为 true
。 如果您想在初始渲染时渲染屏幕,请将其设置为 false
。
drawerLabel
字符串或一个函数,给定 { focused: boolean, color: string }
返回一个 React.Node,以在抽屉侧边栏中显示。 未定义时,使用场景 title
。
drawerIcon
函数,给定 { focused: boolean, color: string, size: number }
返回一个 React.Node 以在抽屉侧边栏中显示。
drawerActiveTintColor
抽屉中活动项目的图标和标签的颜色。

drawerActiveTintColor: 'green',
drawerActiveBackgroundColor
抽屉中活动项目的背景颜色。

screenOptions={{
drawerActiveTintColor: 'white',
drawerActiveBackgroundColor: '#003CB3',
drawerLabelStyle: {
color: 'white',
},
}}
drawerInactiveTintColor
抽屉中非活动项目的图标和标签的颜色。
drawerInactiveBackgroundColor
抽屉中非活动项目的背景颜色。
drawerItemStyle
单个项目的样式对象,可以包含图标和/或标签。

示例
drawerItemStyle: {
backgroundColor: '#9dd3c8',
borderColor: 'black',
orderWidth: 2,
opacity: 0.6,
},
drawerLabelStyle
应用于内容部分内部 Text
样式的样式对象,该样式对象渲染标签。

示例
drawerLabelStyle: {
color: 'black',
fontSize: 20,
fontFamily: 'Georgia',
},
drawerContentContainerStyle
ScrollView
内部内容部分的样式对象。
drawerContentStyle
包装器视图的样式对象。
drawerStyle
抽屉组件的样式对象。 您可以在此处传递抽屉的自定义背景颜色或自定义宽度。

<Drawer.Navigator
screenOptions={{
drawerStyle: {
backgroundColor: '#c6cbef',
width: 240,
},
}}
>
{/* screens */}
</Drawer.Navigator>
drawerPosition
选项为 left
或 right
。 对于 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.navigator
的 screenOptions
属性或 Drawer.Screen
的 options
属性下指定。 您不必直接使用 @react-navigation/elements
即可使用这些选项,它们只是在该页面中进行了文档化。
除了这些之外,抽屉还支持以下选项
header
要使用的自定义标题,而不是默认标题。
这接受一个返回 React 元素的函数以显示为标题。 该函数接收一个对象,该对象包含以下属性作为参数
navigation
- 当前屏幕的导航对象。route
- 当前屏幕的路由对象。options
- 当前屏幕的选项layout
- 屏幕的尺寸,包含height
和width
属性。
示例
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>
);
}
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>
);
}
如果您正在使用类组件,则可以使用 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 之上呈现。