多個抽屜
有時候我們想要在同一個畫面中有多個抽屜:一個在左邊,一個在右邊。這可以用 2 種方法達成
- 直接使用
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>
);
}
但有一個問題。當我們在我們的「主畫面」中呼叫 `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` 函式到「主畫面」。然後我們使用 `openRightDrawer` 來開啟右邊的抽屜。
巢狀兩個抽屜導航器
一種替代方法是在彼此內部巢狀兩個抽屜導航器。不建議這樣做,因為它需要建立一個額外的畫面和更多巢狀結構,這會讓導航和類型檢查變得更冗長。但如果兩個導航器都包含多個畫面,這樣做可能會有用。
在這裡我們有 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>
);
}
但有一個問題。當我們在我們的「主畫面」中呼叫 `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
prop 來指定理想的 Drawer。