抽屉导航器
抽屉导航器在屏幕侧面呈现一个导航抽屉,可以通过手势打开和关闭。
这包装了 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
。如果你有一个 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 1 和最新版本的 Reanimated。如果您想使用最新版本的 Reanimated,请确保按照 安装指南 进行配置。
-
要完成
react-native-gesture-handler
的安装,请在您的入口文件(例如index.js
或App.js
)的顶部添加以下内容(确保它位于顶部,并且之前没有任何其他内容)。import 'react-native-gesture-handler';
警告如果您正在为 Android 或 iOS 构建,请不要跳过此步骤,否则您的应用程序可能会在生产环境中崩溃,即使它在开发环境中运行良好。这并不适用于其他平台。
-
如果您使用的是 Mac 并为 iOS 开发,您还需要安装 pod(通过 Cocoapods)来完成链接。
npx pod-install ios
API 定义
要使用此抽屉导航器,请从 @react-navigation/drawer
中导入它。
import { createDrawerNavigator } from '@react-navigation/drawer';
const Drawer = createDrawerNavigator();
function MyDrawer() {
return (
<Drawer.Navigator>
<Drawer.Screen name="Feed" component={Feed} />
<Drawer.Screen name="Article" component={Article} />
</Drawer.Navigator>
);
}
有关完整的使用指南,请访问 抽屉导航。
属性
Drawer.Navigator
组件接受以下属性
id
导航器的可选唯一 ID。这可以与 navigation.getParent
一起使用,以在子导航器中引用此导航器。
initialRouteName
在导航器首次加载时要渲染的路由的名称。
screenOptions
用于导航器中屏幕的默认选项。
backBehavior
此属性控制在导航器中调用 goBack
时发生的事情。这包括按下设备的返回按钮或 Android 上的返回手势。
它支持以下值
firstRoute
- 返回到导航器中定义的第一个屏幕(默认)initialRoute
- 返回到initialRouteName
属性中传递的初始屏幕,如果未传递,则默认为第一个屏幕order
- 返回到聚焦屏幕之前的屏幕history
- 返回到导航器中最后访问的屏幕;如果同一个屏幕被访问多次,则历史记录中的旧条目将被删除none
- 不处理返回按钮
defaultStatus
抽屉的默认状态 - 抽屉默认情况下应该是 open
还是 closed
。
当此属性设置为 open
时,抽屉将在初始渲染时打开。可以使用手势或以编程方式将其正常关闭。但是,在返回时,如果抽屉已关闭,它将重新打开。这本质上与抽屉的默认行为相反,抽屉默认情况下是 closed
,返回按钮会关闭打开的抽屉。
detachInactiveScreens
布尔值,用于指示是否应将非活动屏幕从视图层次结构中分离以节省内存。这允许与 react-native-screens 集成。默认为 true
。
useLegacyImplementation
是否使用基于 Reanimated 1 的旧实现。基于 Reanimated 2 的新实现将执行得更好,但您需要额外的配置,并且需要使用 Hermes 和 Flipper 进行调试。
在以下情况下,此属性默认为 true
- 未配置 Reanimated 2
- 应用程序连接到 Chrome 调试器(Reanimated 2 无法与 Chrome 调试器一起使用)
- 应用程序在 Web 上运行
否则,它默认为 false
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
组件接受以下 props
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
的样式对象。
progress
对象可用于在 drawerContent
中进行有趣的动画,例如抽屉内容的视差运动。
function CustomDrawerContent(props) {
const progress = useDrawerProgress();
// If you are on react-native-reanimated 1.x, use `Animated.interpolate` instead of `Animated.interpolateNode`
const translateX = Animated.interpolateNode(progress, {
inputRange: [0, 1],
outputRange: [-100, 0],
});
return (
<Animated.View style={{ transform: [{ translateX }] }}>
{/* ... drawer contents */}
</Animated.View>
);
}
progress
对象是 Reanimated Node
(如果您使用的是 Reanimated 1,请参见 useLegacyImplementation
),否则是 SharedValue
。它表示抽屉的动画位置(0 为关闭;1 为打开)。
请注意,您**不能**在drawerContent
中使用useNavigation
钩子,因为useNavigation
仅在屏幕内可用。您可以使用drawerContent
的navigation
道具代替。
function CustomDrawerContent({ navigation }) {
return (
<Button
title="Go somewhere"
onPress={() => {
// Navigate using the `navigation` prop that you received
navigation.navigate('SomeScreen');
}}
/>
);
}
要使用自定义组件,我们需要将其传递给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
抽屉中活动项目中图标和标签的颜色。
drawerActiveBackgroundColor
抽屉中活动项目的背景颜色。
drawerInactiveTintColor
抽屉中非活动项目中图标和标签的颜色。
drawerInactiveBackgroundColor
抽屉中非活动项目的背景颜色。
drawerItemStyle
单个项目的样式对象,可以包含图标和/或标签。
drawerLabelStyle
应用于内容部分中渲染标签的Text
样式的样式对象。
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
时,抽屉将在拉出抽屉或处于“打开”状态时隐藏操作系统状态栏。
drawerStatusBarAnimation
隐藏状态栏时的动画。与 hideStatusBar
结合使用。
支持的值
slide
fade
none
仅在 iOS 上支持。默认值为 slide
。
overlayColor
抽屉打开时,在内容视图顶部显示的颜色叠加层。当抽屉打开时,不透明度从 0
动画到 1
。
sceneContainerStyle
包装屏幕内容的组件的样式对象。
gestureHandlerProps
传递给底层平移手势处理程序的道具。
Web 上不支持。
swipeEnabled
是否可以使用滑动手势打开或关闭抽屉。默认值为 true
。
Web 上不支持滑动手势。
swipeEdgeWidth
允许定义滑动手势应在内容视图边缘多远的地方激活。
Web 上不支持。
swipeMinDistance
应激活打开抽屉的最小滑动距离阈值。
keyboardDismissMode
滑动手势开始时是否应关闭键盘。默认值为 'on-drag'
。设置为 'none'
以禁用键盘处理。
unmountOnBlur
当导航离开此屏幕时,是否应卸载此屏幕。卸载屏幕会重置屏幕中的任何本地状态以及屏幕中嵌套导航器的状态。默认值为 false
。
通常,我们不建议启用此道具,因为用户不希望在切换屏幕时丢失其导航历史记录。如果您启用了此道具,请考虑这是否会真正为用户提供更好的体验。
freezeOnBlur
布尔值,指示是否阻止非活动屏幕重新渲染。默认值为 false
。当从 react-native-screens
包中运行 enableFreeze()
时,默认值为 true
。
需要 react-native-screens
版本 >=3.16.0。
仅在 iOS 和 Android 上支持。
与标题相关的选项
您可以在 此处 找到与标题相关的选项列表。这些 选项 可以指定在 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
};
请注意,此样式默认情况下不会应用于标题,因为您控制自定义标题的样式。如果您还想将此样式应用于您的标题,请使用 props 中的 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
- string - 要跳转到的路由的名称。params
- object - 传递给目标路由的屏幕参数。
navigation.jumpTo('Profile', { owner: 'Satya' });
示例
import { createDrawerNavigator } from '@react-navigation/drawer';
const Drawer = createDrawerNavigator();
function MyDrawer() {
return (
<Drawer.Navigator initialRouteName="Feed">
<Drawer.Screen
name="Feed"
component={Feed}
options={{ drawerLabel: 'Home' }}
/>
<Drawer.Screen
name="Notifications"
component={Notifications}
options={{ drawerLabel: 'Updates' }}
/>
<Drawer.Screen
name="Profile"
component={Profile}
options={{ drawerLabel: 'Profile' }}
/>
</Drawer.Navigator>
);
}
检查抽屉是否打开
您可以使用 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 之上。