Skip to main content
Version: 6.x

多个抽屉

有时我们希望在同一个屏幕上有多个抽屉:一个在左边,一个在右边。这可以通过两种方式实现:

¥Sometimes we want to have multiple drawers on the same screen: one on the left and one on the right. This can be achieved in 2 ways:

  1. 直接使用 react-native-drawer-layout(推荐)。

    ¥By using react-native-drawer-layout directly (Recommended).

  2. 截至 nesting 2 抽屉导航器

    ¥By nesting 2 drawer navigators.

使用 react-native-drawer-layout

¥Using react-native-drawer-layout

当我们有多个抽屉时,只有其中一个显示屏幕列表。第二个抽屉通常用于显示一些附加信息,例如用户列表等。

¥When we have multiple drawers, only one of them shows the list of screens. The second drawer may often be used to show some additional information such as the list of users etc.

在这种情况下,我们可以直接使用 react-native-drawer-layout 来渲染第二个抽屉。抽屉导航器将用于渲染第一个抽屉,并且可以嵌套在第二个抽屉内:

¥In such cases, we can use react-native-drawer-layout directly to render the second drawer. The drawer navigator will be used to render the first drawer and can be nested inside the second drawer:

import * as React from 'react';
import { Button, View } from 'react-native';
import { Drawer } from 'react-native-drawer-layout';
import { createDrawerNavigator } from '@react-navigation/drawer';

function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button onPress={() => navigation.openDrawer()} title="Open drawer" />
</View>
);
}

const LeftDrawer = createDrawerNavigator();

const LeftDrawerScreen = () => {
return (
<LeftDrawer.Navigator screenOptions={{ drawerPosition: 'left' }}>
<LeftDrawer.Screen name="Home" component={HomeScreen} />
</LeftDrawer.Navigator>
);
};

function RightDrawerScreen() {
const [rightDrawerOpen, setRightDrawerOpen] = React.useState(false);

return (
<Drawer
open={rightDrawerOpen}
onOpen={() => setRightDrawerOpen(true)}
onClose={() => setRightDrawerOpen(false)}
drawerPosition="right"
renderDrawerContent={() => <>{/* Right drawer content */}</>}
>
<LeftDrawerScreen />
</Drawer>
);
}

export default function App() {
return (
<NavigationContainer>
<RightDrawerScreen />
</NavigationContainer>
);
}

但有一个问题。当我们在 HomeScreen 中调用 navigation.openDrawer() 时,它总是打开左边的抽屉。我们无法通过 navigation 属性访问右侧抽屉,因为它不是导航器。

¥But there is one problem. When we call navigation.openDrawer() in our HomeScreen, it always opens the left drawer. We don't have access to the right drawer via the navigation prop since it's not a navigator.

为了解决这个问题,我们需要使用 context API 来传递一个函数来控制右侧的抽屉:

¥To solve this, we need to use context API to pass down a function to control the right drawer:

import * as React from 'react';
import { Button, View } from 'react-native';
import { Drawer } from 'react-native-drawer-layout';
import { createDrawerNavigator } from '@react-navigation/drawer';

const RightDrawerContext = React.createContext();

function HomeScreen({ navigation }) {
const { openRightDrawer } = React.useContext(RightDrawerContext);

return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
onPress={() => navigation.openDrawer()}
title="Open left drawer"
/>
<Button onPress={() => openRightDrawer()} title="Open right drawer" />
</View>
);
}

const LeftDrawer = createDrawerNavigator();

const LeftDrawerScreen = () => {
return (
<LeftDrawer.Navigator screenOptions={{ drawerPosition: 'left' }}>
<LeftDrawer.Screen name="Home" component={HomeScreen} />
</LeftDrawer.Navigator>
);
};

function RightDrawerScreen() {
const [rightDrawerOpen, setRightDrawerOpen] = React.useState(false);

const value = React.useMemo(
() => ({
openRightDrawer: () => setRightDrawerOpen(true),
closeRightDrawer: () => setRightDrawerOpen(false),
}),
[]
);

return (
<Drawer
open={rightDrawerOpen}
onOpen={() => setRightDrawerOpen(true)}
onClose={() => setRightDrawerOpen(false)}
drawerPosition="right"
renderDrawerContent={() => <>{/* Right drawer content */}</>}
>
<RightDrawerContext.Provider value={value}>
<LeftDrawerScreen />
</RightDrawerContext.Provider>
</Drawer>
);
}

export default function App() {
return (
<NavigationContainer>
<RightDrawerScreen />
</NavigationContainer>
);
}

在这里,我们使用 RightDrawerContextopenRightDrawer 功能传递给 HomeScreen。然后我们用 openRightDrawer 打开右边的抽屉。

¥Here, we are using the RightDrawerContext to pass down the openRightDrawer function to the HomeScreen. Then we use openRightDrawer to open the right drawer.

嵌套 2 个抽屉导航器

¥Nesting 2 drawer navigators

另一种方法是将 2 个 抽屉导航器 嵌套在彼此内部。不建议这样做,因为它需要创建额外的屏幕和更多的嵌套 - 这会使导航和类型检查更加冗长。但如果两个导​​航器都包含多个屏幕,这可能会很有用。

¥An alternative approach is to nest 2 drawer navigators inside each other. This is not recommended since it requires creating an additional screen and more nesting - which can make navigating and type checking more verbose. But this can be useful if both navigators include multiple screens.

这里我们有 2 个抽屉式导航器,彼此嵌套,一个位于左侧,另一个位于右侧:

¥Here we have 2 drawer navigators nested inside each other, one is positioned on left and the other on the right:

import * as React from 'react';
import { Button, View } from 'react-native';
import { createDrawerNavigator } from '@react-navigation/drawer';
import { NavigationContainer } from '@react-navigation/native';

function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button onPress={() => navigation.openDrawer()} title="Open drawer" />
</View>
);
}

const LeftDrawer = createDrawerNavigator();

const LeftDrawerScreen = () => {
return (
<LeftDrawer.Navigator screenOptions={{ drawerPosition: 'left' }}>
<LeftDrawer.Screen name="Home" component={HomeScreen} />
</LeftDrawer.Navigator>
);
};

const RightDrawer = createDrawerNavigator();

const RightDrawerScreen = () => {
return (
<RightDrawer.Navigator
screenOptions={{ drawerPosition: 'right', headerShown: false }}
>
<RightDrawer.Screen name="HomeDrawer" component={LeftDrawerScreen} />
</RightDrawer.Navigator>
);
};

export default function App() {
return (
<NavigationContainer>
<RightDrawerScreen />
</NavigationContainer>
);
}

但有一个问题。当我们在 HomeScreen 中调用 navigation.openDrawer() 时,它总是打开左侧抽屉,因为它是屏幕的直接父级。

¥But there is one problem. When we call navigation.openDrawer() in our HomeScreen, it always opens the left drawer since it's the immediate parent of the screen.

为了解决这个问题,我们需要使用 navigation.getParent 来引用右抽屉,它是左抽屉的父抽屉。所以我们的代码看起来像:

¥To solve this, we need to use navigation.getParent to refer to the right drawer which is the parent of the left drawer. So our code would look like:

<Button onPress={() => navigation.openDrawer()} title="Open left drawer" />
<Button onPress={() => navigation.getParent().openDrawer()} title="Open right drawer" />

然而,这意味着我们的按钮需要了解父导航器,这并不理想。如果我们的按钮进一步嵌套在其他导航器中,则需要多次 getParent() 调用。为了解决这个问题,我们可以使用 id 属性 来识别父导航器。

¥However, this means that our button needs to know about the parent navigators, which isn't ideal. If our button is further nested inside other navigators, it'd need multiple getParent() calls. To address this, we can use the id prop to identify the parent navigator.

要自定义抽屉的内容,我们可以使用 drawerContent 属性 传入呈现自定义组件的函数。

¥To customize the contents of the drawer, we can use the drawerContent prop to pass in a function that renders a custom component.

最终代码如下所示:

¥The final code would look like this:

import * as React from 'react';
import { Button, Text, View } from 'react-native';
import { createDrawerNavigator } from '@react-navigation/drawer';
import { NavigationContainer } from '@react-navigation/native';

function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
onPress={() => navigation.getParent('LeftDrawer').openDrawer()}
title="Open left drawer"
/>
<Button
onPress={() => navigation.getParent('RightDrawer').openDrawer()}
title="Open right drawer"
/>
</View>
);
}

function RightDrawerContent() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>This is the right drawer</Text>
</View>
);
}

const LeftDrawer = createDrawerNavigator();

function LeftDrawerScreen() {
return (
<LeftDrawer.Navigator
id="LeftDrawer"
screenOptions={{ drawerPosition: 'left' }}
>
<LeftDrawer.Screen name="Home" component={HomeScreen} />
</LeftDrawer.Navigator>
);
}

const RightDrawer = createDrawerNavigator();

function RightDrawerScreen() {
return (
<RightDrawer.Navigator
id="RightDrawer"
drawerContent={(props) => <RightDrawerContent {...props} />}
screenOptions={{
drawerPosition: 'right',
headerShown: false,
}}
>
<RightDrawer.Screen name="HomeDrawer" component={LeftDrawerScreen} />
</RightDrawer.Navigator>
);
}

export default function App() {
return (
<NavigationContainer>
<RightDrawerScreen />
</NavigationContainer>
);
}

在这里,我们在抽屉导航器的 id 属性中传递 "LeftDrawer""RightDrawer" 字符串(你可以在此处使用任何字符串)。然后我们用 navigation.getParent('LeftDrawer').openDrawer() 打开左边的抽屉,用 navigation.getParent('RightDrawer').openDrawer() 打开右边的抽屉。

¥Here, we are passing "LeftDrawer" and "RightDrawer" strings (you can use any string here) in the id prop of the drawer navigators. Then we use navigation.getParent('LeftDrawer').openDrawer() to open the left drawer and navigation.getParent('RightDrawer').openDrawer() to open the right drawer.

概括

¥Summary