이번엔 react native의 react navigation의 하위 라이브러리라 할 수 있는 drawer에 대해서 알아보겠습니다.
일단 모든 관련 라이브러리를 설치하고
npm i @react-navigation/native (모든 navigation 라이브러리를 사용하기 위한 필수 라이브러리)
npm i react-native-screens react-native-safe-area-context (필수 dependencies 라이브러리)
npm i @react-navigation/drawer (drawer 네비게이션)
npm i react-native-reanimated react-native-gesture-handler (필수 dependencies 라이브러리)
(설치한 모든 라이브러리는 package.json 파일의 dependencies항목에서 볼 수 있습니다.)
이제 코딩을 봅시다. 가장 기본적인 App.js 화면을 봅니다.
import React from 'react';
import { View, Text} from 'react-native';
const App = () => {
return (
<View>
<Text>Hello React Navigation!</Text>
</View>
);
};
export default App;
가장 기본적인 화면을 하나 만듭니다.
그다음 기본적인 Drawer 화면을 구성하기 위하여 다음과 같이 작성해봅니다.
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { NavigationContainer } from '@react-navigation/native'; // 네비게이션 컨테이너
import { createDrawerNavigator } from '@react-navigation/drawer'; // Drawer 네비게이션
function Page1({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: 'steelblue' }}>
<Text>Page1</Text>
</View>
);
}
function Page2({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: 'gold'}}>
<Text>Page2</Text>
</View>
);
}
const Drawer = createDrawerNavigator(); // Drawer Navigation함수를 Drawer변수명으로 저장
const App = () => {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="P1">
<Drawer.Screen name="P1" component={Page1} />
<Drawer.Screen name="P2" component={Page2} />
</Drawer.Navigator>
</NavigationContainer>
);
};
export default App;
이제 하나하나 Drawer를 조정해 봅시다.
1. header 없애기.
개인적으로 react-navigation 관련 라이브러리를 이용할 경우 항상 header는 지웁니다.
header가 미리 있어서 편할 수 있지만 내가 원하는 대로 수정하기가 오히려 더 불편합니다...
<Drawer.Navigator initialRouteName="P1" screenOptions={{headerShown: false}}>
<Drawer.Navigator />의 screenOptions 에 headerShown을 false로 줍니다.
2. Drawer를 위의 상태바 위로 보이게 하기.
위의 움짤을 보면 위의 휴대폰의 기본정보를 표시해주는 상태바 아래로 drawer가 움직여서 약간 답답한 느낌이 있습니다. 그러기 위해서는 <StatusBar /> 를 사용해 줍니다. Drawer뿐만 아니라 기본적인 페이지 View에서 적용될 수 있습니다.
import React from 'react';
import { View, Text, TouchableOpacity, StatusBar } from 'react-native';
import { NavigationContainer } from '@react-navigation/native'; // 네비게이션 컨테이너
import { createDrawerNavigator } from '@react-navigation/drawer'; // Drawer 네비게이션
function Page1({ navigation }) {
return (
<View style={{ flex: 1, backgroundColor: 'steelblue' }}>
<StatusBar translucent backgroundColor="rgba(0,0,0,0)" animated/>
<Text style={{fontSize:30}}>Page1</Text>
</View>
);
}
function Page2({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: 'gold'}}>
<Text>Page2</Text>
</View>
);
}
const Drawer = createDrawerNavigator(); // Drawer Navigation함수를 Drawer변수명으로 저장
const App = () => {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="P1" screenOptions={{headerShown: false}}>
<Drawer.Screen name="P1" component={Page1} />
<Drawer.Screen name="P2" component={Page2} />
</Drawer.Navigator>
</NavigationContainer>
);
};
export default App;
일부러 Page1의 Align을 삭제해서 페이지의 시작이 상태바(StatusBar)까지 침범한 것을 표현했습니다.
이제 본격적으로 Drawer 화면을 수정할 수 있는 다양한 Props(Properties)를 알아보겠습니다.
3. drawerContent
Drawer 안의 디자인은 <Drawer.Navigator /> 안에 drawerContent Props를 이용합니다.
먼저 맨 위의 라이브러리 함수 Import부분에 createDrawerNavigator 외에도 DrawerContentScrollView, DrawerItemList, DrawerItem 세 함수를 추가합니다.
그리고 Drawer.Navigator안에 drawerContent Props를 이용하여 새로운 함수(페이지)를 반환합니다.
그리고 그 새로운 페이지는 별도의 함수로 만들어주고 <View>가 아닌 <DrawerContentScrollView>로 둘러싼 페이지를 만들어 줍니다.
import React from 'react';
import { View, Text, TouchableOpacity, StatusBar } from 'react-native';
import { NavigationContainer } from '@react-navigation/native'; // 네비게이션 컨테이너
import { createDrawerNavigator, DrawerContentScrollView, DrawerItemList, DrawerItem } from '@react-navigation/drawer'; // Drawer 네비게이션
function Page1({ navigation }) {
return (
<View style={{ flex: 1, backgroundColor: 'steelblue' }}>
<StatusBar translucent backgroundColor="rgba(0,0,0,0)" animated/>
<Text style={{fontSize:30}}>Page1</Text>
</View>
);
}
function Page2({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: 'gold'}}>
<Text>Page2</Text>
</View>
);
}
function CustomDrawerContent(props) {
return (
<DrawerContentScrollView {...props} style={{backgroundColor:"seagreen"}}>
<DrawerItemList {...props}/>
<DrawerItem label="help" onPress={() => alert("추가 하는 Item")} />
</DrawerContentScrollView>
)
}
const Drawer = createDrawerNavigator(); // Drawer Navigation함수를 Drawer변수명으로 저장
const App = () => {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="P1" screenOptions={{headerShown: false}}
drawerContent={(props) => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="P1" component={Page1} />
<Drawer.Screen name="P2" component={Page2} />
</Drawer.Navigator>
</NavigationContainer>
);
};
export default App;
<DrawerContentView> 안의 <DrawerItemList> 은 이전 <Drawer.Navigator>안의 <Drawer.Screen>을 보여주고 또 <DrawerItem>은 그 외에 추가하고 싶은 항목을 넣습니다. 사실 <DrawerItem>대신 <View>를 써도 되나 <DrawerItemList>와 동일한 디자인 버튼을 만들기 위함입니다.
하지만 위와 같이 제가 Drawer 배경색을 녹색으로 하니 글자색이나 버튼이 잘 보이지 않는데 <DrawerItem>의 경우 최소한의 디자인을 바꿀수 있는 옵션이 있지만 <DrawerItemList>의 경우는 끝내 못찾았습니다. 왜 이렇게 불편하게 만들었는지 모르겠지만 결론은 최초 만든 Page1과 Page2로 이동하는 링크를 <DrawerItem>으로 만들어 봅시다.
중요한 점은 drawerContent 를 통해 <CustomDrawerContent />를 불러올 때 위와 같이 꼭 인자(props)를 불러 오는 것입니다. 결국 이 인자가 각 페이지 <Drawer.Screen>에 대한 정보를 가져온다고 보면 됩니다.
import React from 'react';
import { View, Text, TouchableOpacity, StatusBar } from 'react-native';
import { NavigationContainer } from '@react-navigation/native'; // 네비게이션 컨테이너
import { createDrawerNavigator, DrawerContentScrollView, DrawerItemList, DrawerItem } from '@react-navigation/drawer'; // Drawer 네비게이션
function Page1({ navigation }) {
return (
<View style={{ flex: 1, backgroundColor: 'steelblue' }}>
<StatusBar translucent backgroundColor="rgba(0,0,0,0)" animated/>
<Text style={{fontSize:30}}>Page1</Text>
</View>
);
}
function Page2({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: 'gold'}}>
<Text>Page2</Text>
</View>
);
}
function CustomDrawerContent(props) {
return (
<DrawerContentScrollView {...props} style={{backgroundColor:"seagreen"}}>
<DrawerItem label="P1" onPress={() => props.navigation.navigate('P1')}
inactiveBackgroundColor="gold"
activeBackgroundColor="steelblue"
activeTintColor="white"
style={{borderWidth:2}}/>
<DrawerItem label="P2" onPress={() => props.navigation.navigate('P2')} inactiveTintColor="gold"/>
</DrawerContentScrollView>
)
}
const Drawer = createDrawerNavigator(); // Drawer Navigation함수를 Drawer변수명으로 저장
const App = () => {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="P1" screenOptions={{headerShown: false}}
drawerContent={(props) => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="P1" component={Page1} />
<Drawer.Screen name="P2" component={Page2} />
</Drawer.Navigator>
</NavigationContainer>
);
};
export default App;
DrawerItem에 onPress를 적용하여 () => props.navigation.navigate("원하는 스크린 name")을 입력하면 됩니다!
일부러 첫번째 <DrawerItem>에는 효과를 주었습니다. 하지만 막상 생각해 보면 DrawerItem도 쓸필요 없이 그냥 처음부터 끝까지 View를 이용하여 일반적인 페이지 작업을 해도 상관 없습니다!
사실 이정도를 배울 수준이면 당연히 본인만의 컨셉을 가진 앱 전체에 일관성 있는 디자인을 원할 것이고 아무래도 위와 같이 여백 등 수정하기 힘든 부분들을 생각하면 첨부터 <View>나 <ScrollView>를 이용해서 만들어도 별 차이가 없습니다. 하지만 한편으론 분명 <DrawerItemList>나 <DrawerItem>을 굳이 이용하는 제가 모르는 이유가 있을 수도 있을 것이라고 생각도 합니다.
결론은 저의 경우엔 그냥 일반 View로 전체 Drawer페이지를 구성했습니다.😁
이제 Bottom-tab만 남았습니다.