얼렁뚱땅
[React Native] Drawer Navigation (tab navigation과 동시에 사용하기) 본문
Drawer Navigation 이란?
숨어있다가 필요할 때 화면 왼쪽 모서리 부분을 누르면 (또는 왼쪽에서 오른쪽으로 드래그를 하면) 나타나는 내비게이션
Drawer Navigation 라이브러리 설치
npm i @react-navigation/drawer
파일, 폴더 구성 (기본 뼈대 구성)
이미 tab navigation이 완성된 상태에서 drawer navigation을 구현하려고 한다.
내가 구현하고 싶은 구조 :
3개의 tab screen 중에서 한가지 tab에서만 drawer navigation이 작동하도록 만들고 싶다!
하지만 'combining tab and drawer navigation' 으로 검색하면 대부분 3개의 tab에서 모두 drawer navigation이 구현되는 예시만 있다. 그래서 일단 내 생각대로 구현을 했기 때문에 실제로 이것이 맞는 방식인지는 잘 모르겠다.
Flow
src 밖 App.js -> src/App.js -> navigations/index.js -> MainTab.js -> InstaDrawer.js -> DrawerContent.js 와 Instagram.js 페이지 가져오기!
MainTab.js는 Tab navigation이 완성된 상태
여기서 InstaDrawer.js 를 추가해서 특정 tab에서만 drawer가 구현되도록 하였다.
중간 삽질
처음에 들었던 생각은 Stack, Tab, Drawer Navigation을 모두 만든 후 <NavigationContainer> 컴포넌트에 넣으면 되겠다이었다. 하지만 그렇게 실행해본 결과 아래와 같은 에러 메세지를 받았다.
Error: Another navigator is already registered for this container. You likely have multiple navigators under a single "NavigationContainer" or "Screen". Make sure each navigator is under a separate "Screen" container. See https://reactnavigation.org/docs/nesting-navigators for a guide on nesting.
<NavigationContainer>에는 하나의 Navgatior만 들어가야 하는 것 같다.
그래서 Tab안에 Drawer를 넣는 방식으로 변경한 것이다.
참고
아래에 링크에 나와 비슷한 생각을 한 사람이 있었다. 기본 구조가 나와 비슷해서 참고했다.
src 밖 App.js
import App from './src/App';
export default App;
모든 코드를 src 폴더 내에서 관리하는 것이 편해서 이렇게 했다.
src/App.js
import React from 'react';
import Navigation from './navigations';
export default function App() {
return <Navigation />;
}
이상하게 <View> component 안에 <Navigation>을 두면 화면이 아무것도 안나타난다. 그래서 일단은 임시로 이렇게 두었다. 나중에 <ThemeProvider>를 사용할 예정. <Navigation> 컴포넌트 가져오기.
navigations/index.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import MainTab from './MainTab';
const Navigation = () => {
return (
<NavigationContainer>
<MainTab />
</NavigationContainer>
);
};
export default Navigation;
반드시 <NavigationContainer>로 감싸주어야 한다. <MainTab> 컴포넌트 가져오기.
navigations/MainTab.js
최종 코드는 너무 길어서 아래 링크 참조
https://dev-sailor.tistory.com/27
<Tab.Screen
name="InstagramD"
component={InstaDrawer}
options={{
tabBarIcon: (props) => TabIcon({ ...props, name: 'instagram' }),
}}
/>
마지막 Instagram tab에서만 Drawer Navigation을 구현하고 싶기 때문에 이곳만 InstaDrawer로 변경해준다. (name은 구현되는 페이지 내부의 이름?과 중복 된다고 warning이 떠서 일단 임시로 'InstagramD'라고 해뒀다.)
Drawer Navigation 구현하기
기본 방식은 stack, tab navigation과 동일하다.
navigations/InstaDrawer.js
import React from 'react';
import { createDrawerNavigator } from '@react-navigation/drawer';
import Instagram from '../screens/Instagram';
const Drawer = createDrawerNavigator();
const InstaDrawer = () => {
return (
<Drawer.Navigator>
<Drawer.Screen name="Instagram" component={Instagram} />
</Drawer.Navigator>
);
};
export default InstaDrawer;
이것도 좋지만 나는 Drawer 내부 페이지를 조금 다르게 꾸미고 싶어서 drawerContent 라는 것을 사용했다.
navigations/InstaDrawer.js
import React from 'react';
import { createDrawerNavigator } from '@react-navigation/drawer';
import DrawerContent from '../screens/DrawerContent';
import Instagram from '../screens/Instagram';
const Drawer = createDrawerNavigator();
const InstaDrawer = () => {
return (
<Drawer.Navigator drawerContent={DrawerContent}>
<Drawer.Screen name="Instagram" component={Instagram} />
</Drawer.Navigator>
);
};
export default InstaDrawer;
screens/DrawerContent.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function DrawerContent() {
return (
<View style={styles.container}>
<Text style={styles.text}>DrawerContent Page</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
text: {
fontSize: 30,
},
});
어느정도 해결 된 것 처럼 보이나 사실 header가 두 번 보이는 문제가 있다. 먼저 나오는 것이 tab navigation의 헤더이고 아래에 나오는 것이 drawer navigation의 헤더이다.
Header 숨기기
사용할 수 있는 설정이 2가지가 있다.
- headerMode
- headerShown
headerMode
Navigator 컴포넌트의 속성으로 헤더를 렌더링하는 방법 설정
- float : 헤더가 상단에 유지되면 하나의 헤더 사용. iOS 동작 방식
- screen : 각 화면마다 헤더를 가지며 화면 변경과 함꼐 나타나거나 사라짐. Andriod 동작 방식
- none : 헤더가 렌더링 되지 않음
hearderShown
화면 옵션
Navigator 컴포넌트의 screenOptions에서 설정하면 전체 화면의 헤더가 보이지 않고
Screen 컴포넌트의 options에서 설정하면 그 화면에서만 헤더가 보이지 않는다.
나는 headerShown : false 를 Instagram 페이지에서만 사용했다.
MainTab.js
<Tab.Screen
name="InstagramD"
component={InstaDrawer}
options={{
headerShown: false,
tabBarIcon: (props) => TabIcon({ ...props, name: 'instagram' }),
}}
/>
Drawer 헤더만 나타나는 것을 확인할 수 있다.
Header 가운데 정렬
하지만 tab navigation의 헤더의 글자 위치와 drawer navigation의 글자 위치가 달라서 통일감이 없다. 헤더를 가운데 정렬 시키고 싶다.
headerTitleAlign 속성을 이용한다.
headerTitleAlign에서는 left와 center 두 가지가 값 중 하나만 설정할 수 있다. iOS는 center로, 안드로이드는 left가 기본값으로 설정되어 있다.
tab navigator header와 drawer navigator header 모두 'center'로 설정해준다.
MainTab.js
<Tab.Navigator
screenOptions={{
tabBarActiveBackgroundColor: 'pink', //터치시 배경
tabBarActiveTintColor: 'black', //터치시 글자색
tabBarInactiveTintColor: 'black', //비터치시 글자색
headerTitleAlign: 'center', //헤더 타이틀 가운데정렬
}}
>
InstaDrawer.js
<Drawer.Navigator
drawerContent={DrawerContent}
screenOptions={{ headerTitleAlign: 'center' }}
>
완성~~~!
'React Native' 카테고리의 다른 글
[React Native] 스타일링 적용 방법(1) (0) | 2021.08.21 |
---|---|
[React Native] Stack Navigation 사용하기 (0) | 2021.08.18 |
[React Native] Tab Navigation 사용하기 (0) | 2021.08.12 |
[React Native] Expo 프로젝트 만들기 (0) | 2021.08.09 |
[React Native] 윈도우에서 React Native 개발 환경 준비 (0) | 2021.08.09 |