React & React Native/라이브러리 활용
[RN] React Native Stack Navigator과 하단 네비게이션(Bottom Tab Navigator) 함께 사용하기 : Nesting Navigators
adjh54
2023. 7. 5. 17:50
반응형
해당 글에서는 Stack Navigator와 Bottom Tab Navigator를 함께 사용하는 Nesting Navigators를 구성하는 방법에 대해서 공유합니다.
1) Stack Navigator
💡 Stack Navigator
- ‘스택 형태’로 화면 위에 새로운 화면을 쌓아서 탐색을 하는 내비게이션 컴포넌트를 의미합니다.
- 스택 형태로 쌓아두기에 이전 화면으로 되돌아갈 수 있으며 탐색 히스토리를 유지하는 특징을 가지고 있습니다. 그렇기에 주로 탐색이 많은 애플리케이션에 적합합니다.
- 예를 들어, A 화면에서 버튼을 누르면 B 화면으로 이동하고, B 화면에서 다시 버튼을 누르면 A 화면으로 돌아오는 경우에 사용할 수 있습니다. 기본적으로 스택 내비게이터는 iOS에서는 새 화면으로 이동 시 오른쪽에서 슬라이드 되고 Andriod에서는 OS 기본 애니메이션이 사용됩니다. (* 해당 애니메이션을 사용자의 선택으로 정의할 수 있음)
[참고] react-native-navigation에 대해 궁금하시면 도움이 됩니다.
2) 하단 내비게이션(Bottom Tab Navigator/ Material Bottom Tabs Navigator)
💡 Bottom Tabs Navigator
- React Native에서 제공하는 내비게이션 라이브러리 중 하나입니다. 이 라이브러리를 사용하면 ‘하단에 위치한 탭 바’를 통해 ‘다른 화면으로 이동’하는 기능을 구현할 수 있습니다.
💡 Material Bottom Tabs Navigator
- 안드로이드 디자인 패턴 중 하나인 Material Design을 기반으로 한 React Native 라이브러리입니다. 이 라이브러리는 ‘하단 탭 내비게이션’을 간편하게 구현할 수 있도록 도와줍니다.
💡 [참고] Navigation 동작은 아래의 링크를 통해서 확인하시면 좀 더 이해하기가 쉽습니다.
1. Bottom Tabs Navigator과 Material Bottom Tabs Navigator 비교
비교 | Bottom Tabs Navigator | Material Bottom Tabs Navigator |
동작 플랫폼 | iOS, Android | Android |
디자인 가이드 | 일반적인 UI/UX | Material 디자인 가이드에 따른 UI/UX |
사용자 정의 기능 | 다양한 옵션 제공 | 제한적인 사용자 정의 기능 |
아이콘 및 라벨 설정 | 가능 | 가능 |
2. Tab.Navigator의 screenOptions 옵션
💡 Tab.Navigator의 screenOptions 옵션
- customBottomTabNaviOptions 값으로 사용되는 속성들에 대한 옵션입니다.
<Tab.Navigator screenOptions={customBottomTabNaviOptions}>
속성 | 설명 |
title | headerTitle 및 tabBarLabel의 대체 제목에 대한 속성 |
tabBarLabel | - 탭 바에서 표시되는 탭의 제목 문자열 또는 { focused : boolean, color : string }를 받아 React.Node를 반환하는 함수. - tabBarShowLabel를 숨기려면 정의하지 않으면 scene title이 사용됩니다. |
tabBarShowLabel | 탭 라벨을 표시할지 여부에 대한 속성 (기본값은 true입니다.) |
tabBarLabelPosition | - 라벨이 아이콘 아래에 표시되는지 옆에 표시되는지 여부에 대한 속성 - below-icon : 라벨이 아이콘 아래에 표시됨 (아이폰의 특징), beside-icon : 라벨이 아이콘 옆에 표시됨 (iPad의 특징). - 기본적으로 기기 너비에 따라 위치가 자동으로 선택됩니다. |
tabBarLabelStyle | 탭 라벨의 스타일 객체 |
tabBarIcon | { focused : boolean, color : string, size : number }를 받아 React.Node를 반환하는 함수. 탭 바에 표시됩니다. |
tabBarIconStyle | 탭 아이콘의 스타일 객체 |
tabBarBadge | 탭 아이콘에 표시할 텍스트. 문자열 또는 숫자를 허용합니다. |
tabBarBadgeStyle | 탭 아이콘에있는 배지의 스타일. 여기에서 배경색이나 글꼴 색상을 지정할 수 있습니다. |
tabBarAccessibilityLabel | 탭 버튼에 대한 접근성 레이블. 사용자가 탭을 누르면 화면 판독기에서 읽습니다. 탭에 레이블이없는 경우 설정하는 것이 좋습니다. |
tabBarTestID | 테스트에서이 탭 버튼을 찾을 ID입니다. |
tabBarButton | 탭 바 버튼으로 렌더링 할 React 요소를 반환하는 함수. 아이콘과 레이블을 둘러싸는 것입니다. 기본적으로Pressable을 렌더링합니다. |
tabBarActiveTintColor | 활성 탭의 아이콘 및 레이블 색상 |
tabBarInactiveTintColor | 비활성 탭의 아이콘 및 레이블 색상 |
tabBarActiveBackgroundColor | 활성 탭의 배경색 |
tabBarInactiveBackgroundColor | 비활성 탭의 배경색 |
tabBarHideOnKeyboard | 키보드가 열릴 때 탭 바를 숨길지 여부. 기본값은 false입니다. |
tabBarItemStyle | 탭 항목 컨테이너의 스타일 개체 |
tabBarStyle | 탭 바의 스타일 개체. 여기에서 배경색과 같은 스타일을 구성할 수 있습니다. |
3) Stack Navigator과 Bottom Tab Navigator 차이
💡 두 가지 Navigator의 경우 다른 탐색 방법입니다.
💡Stack Navigation은 화면 위에 새로운 화면을 쌓아서 탐색하는 방법입니다.
- 이전에 본 화면으로 돌아갈 수 있으며, 탐색 히스토리를 유지합니다. 이 방법은 주로 탐색이 많은 애플리케이션에 적합합니다.
💡 Bottom Tab Navigator는 화면 아래에 탭을 사용하여 탐색하는 방법입니다.
- 각 탭은 별도의 화면을 나타내며, 탭 간 전환을 위해 사용자가 탭을 클릭하거나 스와이프 할 수 있습니다. 이 방법은 탐색이 적은 애플리케이션에 적합합니다.
분류 | Stack Navigator | Bottom Tab Navigator |
설명 | 화면 위에 새로운 화면을 쌓아서 탐색하는 방법 : 계층적 네비게이션 | 화면 아래에 탭을 사용하여 탐색하는 방법 : 평면적 네비게이션 |
화면전환 | 이전 페이지로 이동이 가능함 | 이전 페이지로 이동이 불가능함 |
적합한 유형 | 페이지 간의 탐색이 많은 애플리케이션에 적합 | 페이지간의 탐색이 적은 애플리케이션에 적합 |
React Navigation 버전 | v1부터 v6까지 지원 | v5부터 v6까지 지원 |
4) Stack Navigator + Bottom Tab Navigator 구현 : Nesting Navigators
💡 해당 부분에서는 이전에 구성한 StackNavigator와 ‘Bottom Tab Navigator’를 선택하여서 중첩된 내비게이터(Nesting Navigators)를 구현하는 부분입니다.
💡 이렇게 구현하는 이유는 하단 탭 Navigator 형태로 사용할 수도 있지만 로그인과 같이 아직 로그인이 안된 상태의 페이지 경우에는 하단의 탭이 필요 없기에 이를 위해서 사용됩니다.
💡 [참고] 공식사이트 Nesting Navigators
1. Stack Navigator 구성
💡 기존의 StackNavigator는 아래의 링크를 확인하시면 구현할 수 있습니다.
2. Bottom Tab Navigator 라이브러리 추가
# Bottom Tab Navigator 라이브러리 설치(yarn)
# npm i @react-navigation/bottom-tabs
# or
# Bottom Tab Navigator 라이브러리 설치(yarn)
$ yarn add @react-navigation/bottom-tabs
3. 구현하기
💡 ‘Stack Navigator’내의 ‘Bottom Tab Navigator’를 추가하는 형태로 구성합니다.
3.1. App.tsx
💡 NavigationContainer내에 StackNavigator를 감싸줍니다.
import { NavigationContainer } from '@react-navigation/native';
import React from 'react';
import StackNavigator from 'screens/navigation/StackNavigator';
/**
* 앱의 메인 화면
*/
const App = () => {
return (
<NavigationContainer>
<StackNavigator />
</NavigationContainer>
)
}
export default App;
4. Stack Navigator 구성
💡 StackNavigator 파일 내에서는 하단 탭이 포함되지 않은 화면과 포함된 화면을 함께 불러옵니다.
- Stack.Screen으로 즉시 불러오는 경우는 하단의 탭을 포함하지 않는 경우로 출력이 됩니다.
- Stack.Screen으로 BottomTabNavigator 컴포넌트를 불러오는 경우는 하단의 탭을 포함하는 경우로 불러옵니다.
import React from 'react'
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator, StackNavigationOptions } from '@react-navigation/stack';
import { CommonType } from 'types/common/CommonType';
import TemplateMainScreen from 'screens/template/TemplateMainScreen';
import BottomTabNavigator from './BottomTabNavigator';
import { Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
/**
* StackNavigator를 이용하여서 앱에 대한 페이지 이동을 관리합니다.
*/
const StackNavigator = (appStateType: any) => {
// StackNavigation을 이용하여 페이지를 관리하며 각각 RootStackPageList에서 페이지를 관리합니다
const Stack = createStackNavigator<CommonType.RootStackPageList>();
return (
// TabBar의 UI는 BottomTabBar 화면에서 관리합니다.
<Stack.Navigator initialRouteName='home'>
{/* 메인 페이지 */}
<Stack.Screen name="home">
{(props) => <Home {...props} appState={appStateType.appState} />}
</Stack.Screen>
{/* 관리자 페이지 */}
<Stack.Screen name="adminScreen" >
{(props) => <AdminScreen {...props} appState={appStateType.appState} />}
</Stack.Screen>
{/* Bottom Tab Navigation을 Stack 내에 추가합니다. */}
<Stack.Screen
name='BottomTabNavigator'
component={BottomTabNavigator}
options={{ headerShown: false }}
/>
</Stack.Navigator>
)
}
export default StackNavigator;
5. StackNavigation 액션 함수
💡 StackNavigation을 이용하여 페이지를 이동하고자 할 때 사용하는 액션 함수에 대해 확인해 봅니다.
메서드 | 설명 | 뒤로가기 가능 여부 |
navigate | 지정된 화면으로 이동합니다. | 가능 |
goBack | 이전 화면으로 돌아갑니다. | 가능 |
push | 새로운 화면을 스택에 추가합니다. | 가능 |
pop | 현재 화면을 스택에서 제거합니다. | 불가능 |
replace | 현재 화면을 다른 화면으로 교체합니다. | 불가능 |
reset | 스택을 초기화하고 새로운 화면으로 이동합니다. | 불가능 |
6. Bottom Tab Navigator 구성
6.1. BottomTabNavigator
💡 BottomTabNavigator 파일 내에서는 BottomTab을 포함시켜서 출력하는 화면들에 대해서 관리합니다.
- Tab.Navigator 내에 Tab.Screen으로 각각을 등록해 줍니다.
- 그리고 또한 Tab.Navigator 내에 tabBar 속성을 이용하여 모바일 상에 출력하는 UI를 관리합니다.
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import React from 'react'
import AdminScreen from 'screens/admin/AdminScreen';
import { Home } from 'screens/Home';
import { CommonType } from 'types/common/CommonType';
import BottomTabBar from './BottomTab';
/**
* Bottom TabBar를 사용하는 경우의 Navigation
* @param appStateType
* @returns
*/
const BottomTabNavigator = (appStateType: any) => {
const Tab = createBottomTabNavigator<CommonType.RootStackPageList>();
return (
// TabBar의 UI는 BottomTabBar 화면에서 관리합니다.
<Tab.Navigator tabBar={props => <BottomTabBar {...props} />} >
{/* 탭1 컴포넌트 페이지 */}
<Tab.Screen name="tab1" >
{(props) => <Tab1 {...props} appState={appStateType.appState} />}
</Tab.Screen>
{/* 탭2 컴포넌트 페이지 */}
<Tab.Screen name="tab2" >
{(props) => <Tab2 {...props} appState={appStateType.appState} />}
</Tab.Screen>
{/* 탭3 컴포넌트 페이지 */}
<Tab.Screen name="tab3" >
{(props) => <Tab3 {...props} appState={appStateType.appState} />}
</Tab.Screen>
{/* 탭4 컴포넌트 페이지 */}
<Tab.Screen name="tab4" >
{(props) => <Tab4 {...props} appState={appStateType.appState} />}
</Stack.Screen>
{/* 탭5 컴포넌트 페이지 */}
<Tab.Screen name="tab5" >
{(props) => <Tab5 {...props} appState={appStateType.appState} />}
</Tab.Screen>
</Tab.Navigator>
)
}
export default BottomTabNavigator;
6.2. BottomTabBar
💡 BottomTabBar 페이지에서는 Bottom Tab Bar의 UI를 구성하며 BottomTabNavigator에 등록된 페이지 정보를 통해서 onPress 함수가 실행될 때 페이지를 전환시켜 줍니다.
import { APP_STATUS, BOTTOM_TAB_MENU_CODE } from 'common/codes/CommonCode';
import React, { useState } from 'react';
import { GestureResponderEvent, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
/**
* 하단의 탭 내비게이션 UI 관리
* @param param0
* @returns
*/
const BottomTabBar = ({ state, navigation }) => {
const bottomMenuText = ["TAB1", "TAB2", "TAB3", "TAB4", "TAB5"]
const [isFocused, setIsFocused] = useState(false);
/**
* 탭 버튼을 눌렀을 때 페이지 이동하기
* @param e
* @param index
*/
const pressBottomTab = (e: GestureResponderEvent, index: number) => {
// index 별로 페이지를 등록하여서 즉시 페이지 이동을 합니다.
navigation.navigate({ name: BOTTOM_TAB_MENU_CODE[index], merge: true });
};
/**
* 탭 버튼을 길게 눌렀을 때 처리
*/
const longPressBottomTab = () => {
}
return (
<View style={styles.container}>
{
bottomMenuText.map((menuText, index) =>
<TouchableOpacity
key={`menuKey-${index}`}
accessibilityRole="button"
onPress={(e) => pressBottomTab(e, index)}
onLongPress={longPressBottomTab}
style={styles.text}
>
<Text style={{ color: isFocused ? '#673ab7' : '#222' }}>
{menuText}
</Text>
</TouchableOpacity>
)
}
</View>
)
}
/**
* [함수] 기본 스타일 적용 함수
*/
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
borderStyle: "solid",
borderWidth: 1,
borderColor: "black",
},
text: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
height: 60
},
})
export default BottomTabBar;
6.3. CommonCode.ts
/**
* Bottom Tap의 메뉴별 인덱스 별로 화면에 등록된 정보를 가져옵니다.
*/
export const BOTTOM_TAB_MENU_CODE = {
0: 'tab1',
1: 'tab2',
2: 'tab3',
3: 'tab4',
4: 'tab5',
}
5) 참고 : Bottom Tab Navigator에서 탭 이동 시 새로고침 하는 방법
💡 Bottom Tab Navigator에서 탭 이동 시 새로고침을 하는 방법은 options={{ unmountOnBlur: true, }} 옵션을 추가하면 됩니다. 그러면 탭을 선택했을 때마다 옵션을 추가한 탭에서는 새로고침이 발생합니다.
<Tab.Navigator initialRouteName='home' tabBar={props => <BottomTabBar {...props} />} >
{/* 메인 페이지 */}
<Tab.Screen name="home" options={{ unmountOnBlur: true }}>
{(props) => <Home {...props} appState={appStateType.appState} />}
</Tab.Screen>
{/* 관리자 페이지 */}
<Tab.Screen name="adminScreen" options={{ unmountOnBlur: true }}>
{(props) => <AdminScreen {...props} appState={appStateType.appState} />}
</Tab.Screen>
</Tab.Navigator >
6) 참고: Bottom Tap Navigator를 여러 개 사용하는 방법
💡 Bottom Tab Navigator를 상황에 따라서 여러 개를 구성하여서 호출하는 방법입니다.
1. Stack Navigator 구성
💡 Stack Navigator내에 두 개의 Bottom Tap Navigator를 등록합니다.
// Stack Navigator의 시작은 Bottom Tab Navigator의 Home 화면이기에 Default 값으로 지정합니다.
<Stack.Navigator screenOptions={customStackNavigationOptions} initialRouteName={"home"}>
{/* Stack Navigator 내에 'Bottom Tab Navigator1'를 등록합니다. */}
<Stack.Screen name="bottomTabNav1" component={BottomTabNavigator1} options={{ headerShown: false }} />
{/* Stack Navigator 내에 'Bottom Tab Navigator2'를 등록합니다. */}
<Stack.Screen name="bottomTabNav2" component={BottomTabNavigator2} options={{ headerShown: false }} />
</Stack.Navigator
2. BottomTabNav1 구성
💡 Bottom Tab Naviagator에서는 tabBar 속성으로 BottomTabBar1이라는 UI를 호출합니다.
<Tab.Navigator
screenOptions={customBottomTabNaviOptions}
tabBar={props => <BottomTabBar1 {...props} />} >
{/* 메인 페이지 */}
<Tab.Screen name="home" options={{ unmountOnBlur: true }}>
{(props) => <Home {...props} appState={appStateType.appState} />}
</Tab.Screen>
</Tab.Navigator >
3. BottomTabNav2 구성
💡 Bottom Tab Naviagator에서는 tabBar 속성으로 BottomTabBar2이라는 UI를 호출합니다.
<Tab.Navigator
screenOptions={customBottomTabNaviOptions}
tabBar={props => <BottomTabBar2 {...props} />} >
{/* 메인 페이지 */}
<Tab.Screen name="study" options={{ unmountOnBlur: true }}>
{(props) => <StudyScreen {...props} appState={appStateType.appState} />}
</Tab.Screen>
</Tab.Navigator >
4. 화면상 호출부
💡 화면상에서 페이지 이동을 위해서는 navigation.navigator를 이용하며, 각각 bottomTabNav1 -> home / bottomTabNav2-> Study로 호출을 하여서 페이지를 이동합니다.
// 1번 Bottom Tap Navigator에 등록되어있는 페이지로 이동합니다.
navigation.navigate('bottomTabNav1', {
screen: 'home',
params: { key: "12o3812390812390" },
});
// 2번 Bottom Tap Navigator에 등록되어있는 페이지로 이동합니다.
navigation.navigate('bottomTabNav2', {
screen: 'study',
params: { key: "369" },
});
오늘도 감사합니다. 😀
반응형