多个抽屉
有时我们希望在同一个屏幕上有多个抽屉:一个在左边,一个在右边。这可以通过两种方式实现
- 直接使用
react-native-drawer-layout
(推荐)。 - 通过 嵌套 2 个 抽屉导航器。
使用 react-native-drawer-layout
当我们有多个抽屉时,只有一个抽屉会显示屏幕列表。第二个抽屉通常用于显示一些额外的信息,例如用户列表等。
在这种情况下,我们可以直接使用 react-native-drawer-layout
来渲染第二个抽屉。抽屉导航器将用于渲染第一个抽屉,并且可以嵌套在第二个抽屉中。
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
属性访问右侧抽屉,因为它不是导航器。
为了解决这个问题,我们需要使用上下文 API 将一个函数传递到控制右侧抽屉。
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>
);
}
在这里,我们使用 RightDrawerContext
将 openRightDrawer
函数传递到 HomeScreen
。然后我们使用 openRightDrawer
来打开右侧抽屉。
嵌套 2 个抽屉导航器
另一种方法是将 2 个 抽屉导航器 互相嵌套。这并不推荐,因为它需要创建额外的屏幕和更多嵌套,这会使导航和类型检查变得更加冗长。但这在两个导航器都包含多个屏幕时可能有用。
这里我们有两个抽屉导航器互相嵌套,一个位于左侧,另一个位于右侧。
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()
时,它总是打开左侧抽屉,因为它是最靠近屏幕的父级。
为了解决这个问题,我们需要使用 navigation.getParent
来引用右侧抽屉,它是左侧抽屉的父级。所以我们的代码看起来像这样
<Button onPress={() => navigation.openDrawer()} title="Open left drawer" />
<Button onPress={() => navigation.getParent().openDrawer()} title="Open right drawer" />
但是,这意味着我们的按钮需要了解父导航器,这不是理想的。如果我们的按钮进一步嵌套在其他导航器中,它将需要多个 getParent()
调用。为了解决这个问题,我们可以使用 id
属性 来标识父导航器。
为了自定义抽屉的内容,我们可以使用 drawerContent
属性 传递一个渲染自定义组件的函数。
最终的代码看起来像这样
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()
来打开右侧抽屉。
总结
- 为了拥有多个抽屉,你可以直接使用
react-native-drawer-layout
与抽屉导航器结合使用。 - 可以使用
drawerPosition
属性将抽屉定位在右侧。 - 当使用
react-native-drawer-layout
时,可以使用上下文 API 将控制抽屉的方法传递下去。 - 当嵌套多个导航器时,可以使用
navigation.getParent
与id
属性 结合使用来引用所需的抽屉。