일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 백준 5525번
- 깃 터미널 연동
- 팀플회고
- 스터디
- 리액트 네이티브
- 백준 4358번
- 백준
- SQL
- 백준 4949번
- 데이터베이스
- 정리
- 데베
- 깃허브 로그인
- 모두를 위한 딥러닝
- 깃 연동
- 모두의네트워크
- 리액트 네이티브 시작하기
- 깃허브 토큰 인증
- 모두의 네트워크
- React Native
- 모두를위한딥러닝
- 자바
- 지네릭스
- 백준 4358 자바
- 딥러닝
- 머신러닝
- 리액트 네이티브 프로젝트 생성
- 네트워크
- 문자열
- HTTP
- Today
- Total
솜이의 데브로그
[React Native] Navigation 본문
Reference : 처음 배우는 리액트 네이티브 (김범준)
모바일 애플리케이션에서 가장 중요한 기능 중 하나인 내비게이션을 만들어보자.
리액트 네이티브에서는 외부 라이브러리를 이용해야한다.
npm install --save @react-navigation/native
리액트 내비게이션은 각 기능별로 모듈이 분리되어 있어 이후에도 사용하는 내비게이션의 종류에 따라 개별적으로 추가 라이브러리를 설치해야한다.
1. 리액트 네비게이션
- 스택 내비게이션
- 탭 내비게이션
- 드로어 내비게이션
내비게이션의 구조
- Screen 컴포넌트 : 화면으로 사용되는 컴포넌트
- name, component 속성을 지정해야한다.
- 항상 navigation과 route가 props로 전달된다.
- Navigation 컴포넌트 : 화면을 관리하는 중간 관리자 역할
- 여러 개의 Screen 컴포넌트를 자식 컴포넌트로 갖고 있다.
- NavigationContainer 컴포넌트 : 내비게이션의 계층 구조와 상태를 관리하는 컨테이너 역할
- 모든 내비게이션 구성 요소를 감싼 최상위 컴포넌트
설정 우선 순위
리액트 내비에기션에서 설정할 수 있는 다양한 속성을 수정하는 방법
- Navigator 컴포넌트의 속성으로 수정
- 자식 컴포넌트로 존재하는 모든 컴포넌트에 적용된다.
- 모든 화면에 공통적으로 적용하고 싶은 속성인 경우 이용
- Screen 컴포넌트의 속성으로 수정
- 화면으로 사용되는 컴포넌트의 props로 전달되는 navigation을 이용해서 수정
- 개별화면에만 적용되는 속성인 경우 Screen 컴포넌트 혹은 화면으로 사용되는 컴포넌트에서 수정
작은 범위의 설정일수록 우선순위가 높으므로, Screen 컴포넌트와 화면으로 사용되는 컴포넌트에 동일한 옵션이 적용되었다면 화면 컴포넌트의 설정이 우선한다.
2. 스택 내비게이션
npm install @react-navigation/stack
- 일반적으로 가장 많이 사용되는 내비게이션
- 현재 화면 위에 다른 화면을 쌓으면서(push) 화면 이동
- 이전 화면을 계속 유지하므로, 가장 위의 화면을 들어내면(pop) 이전화면으로 돌아간다.
- 여러 목록 중 특정 항목의 상세 화면으로 이동할 때 많이 사용
화면 구성
src/Screens
- 첫 화면으로 사용할 Home 화면 작성
const Home = () => {
return(
<Container>
<StyledText>Home</StyledText>
<Button title="go to the list screen" />
</Container>
);
};
export default Home;
- List 화면으로 사용될 컴포넌트 작성 : 화면에서 사용할 임시 목록 생성 후, 항목 수만큼 버튼을 생성
- 목록의 상세정보를 보여주는 컴포넌트 작성
src/navigations
const Stack = createStackNavigator();
const StackNavigation = () => {
return(
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="List" component={List} />
<Stack.Screen name="Item" component={Item} />
</Stack.Navigator>
);
};
- createStackNavigator 함수를 이용해 스택 내비게이션을 생성
- 생성된 스택 내비게이션에는 화면을 구성하는 Screen 컴포넌트와 Screen 컴포넌트를 관리하는 Navigator 컴포넌트가 있다.
- Navigator 컴포넌트 안에 Screen 컴포넌트를 자식 컴포넌트로 작성하고, 만든 컴포넌트를 Screen 컴포넌트의 component로 지정한다.
src/App.js
const App = () => {
return (
<NavigationContainer>
<StackNavigation/>
</NavigationContainer>
);
};
NavigationContainer 컴포넌트를 이용해 작성된 스택 내비게이션을 감싸도록 한다.
→ 첫 번째로 나오는 화면은 Navigator 컴포넌트의 첫번째 자식 Screen 컴포넌트이다.
- 컴포넌트의 순서 변경 또는 initialRouteName 속성을 이용해 첫 번째 화면을 지정할 수 있다.
화면 이동
- Screen 컴포넌트의 component로 지정된 컴포넌트는 화면으로 이용되고 navigation이 props로 전달된다.
- navigate 함수 : 원하는 화면으로 이동
Home 화면에서 props로 전달되는 navigation을 사용해서 버튼을 클릭하면 List 화면으로 이동하도록 해보자.
const Home = ({ navigation }) => {
return(
<Container>
<StyledText>Home</StyledText>
<Button
title="go to the list screen"
onPress={() => navigation.navigate('List')}
/>
</Container>
);
};
- navigation에 있는 navigate 함수를 이용해서 원하는 화면의 이름을 전달하면 해당 화면으로 이동한다.
- 전달되는 화면 이름은 Screen 컴포넌트의 name 값 중 하나를 입력
navigate 함수 이용 시 두 번째 파라미터에 객체를 전달해서 이동하는 화면에 필요한 정보를 함께 전달 할 수 있다.
const List = ({ navigation }) => {
const _onPress = item => {
navigation.navigate('Item', { id: item._id, name: item.name });
};
Item 화면으로 이동하면서 항목의 id와 name을 함께 전달하도록 한다.
전달된 내용은 컴포넌트의 props로 전달되는 route의 params를 통해 확인 가능하다.
const Item = ({ route }) => {
return(
<Container>
<StyledText>Item</StyledText>
<StyledText>Id: {route.params.id}</StyledText>
<StyledText>Name: {route.params.name}</StyledText>
</Container>
);
};
전달받은 params를 이용하여 화면에 id와 name을 출력한다.
화면 배경색 수정하기
src/screens/Home.js
const Container = styled.View`
background-color: #ffffff;
align-items: center;
`;
- 화면 컴포넌트가 전체 영역을 차지하도록 스타일에 flex: 1 을 설정한다.
- 상황에 따라 화면 전체를 차지하지 못하는 경우 리액트 내비게이션의 설정을 수정하여 해결한다.
-
const StackNavigation = () => { return( <Stack.Navigator initialRouteName="Home" screenOptions={{ cardStyle: {backgroundColor: '#ffffff'} }} >
- cardStyle을 이용해 스택 내비게이션의 화면 배경색 수정.
- 화면 배경색은 일반적으로 동일하게 사용하므로 화면마다 설정하기보다 Navigation 컴포넌트에서 설정해 화면 전체에 적용되도록 하는 것이 편리하다.
- 특정화면만 배경색을 다르게 지정하고 싶은 경우 Screen 컴포넌트에서 설정하거나 화면으로 사용되는 컴포넌트에서 직접 배경색을 지정한다.
헤더 수정하기
스택 내비게이션의 헤더는 뒤로 가기 버튼을 제공하거나 타이틀을 통해 현재 화면을 알려준다.
타이틀 수정
- Screen 컴포넌트의 name 속성을 기본값으로 사용 → name을 수정하는 것이 가장 쉽게 타이틀 변경하는 법.
- name 값 변경 시 navigate 함수에 전달하는 첫 번째 파라미터값도 변경되어야 한다.
-
const List = ({ navigation }) => { const _onPress = item => { navigation.navigate('Detail', { id: item._id, name: item.name }); };
- name 속성을 이용하는 곳을 모두 찾아 수정해야한다는 단점이 있다.
다른 방법으로는 headerTitle 속성을 이용하는 법이 있다.
const StackNavigation = () => {
return(
<Stack.Navigator
initialRouteName="Home"
screenOptions={{ cardStyle: {backgroundColor: '#ffffff'} }}
>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen
name="List"
component={List}
options={{ headerTitle: 'List Screen' }}
/>
<Stack.Screen name="Detail" component={Item} />
</Stack.Navigator>
);
};
개별 화면을 수정하고 싶은 경우 Screen 컴포넌트의 options를 이용한다.
모든 화면에서 같은 타이틀이 나타나도록 수정하고 싶으면 Navigator 컴포넌트의 screenOptions 속성에 headerTitle을 지정한다.
스타일 수정
- headerStyle : 헤더의 배경색 등을 수정
- headerTitleStyle : 헤더의 타이틀 컴포넌트의 스타일 수정
const StackNavigation = () => {
return(
<Stack.Navigator
initialRouteName="Home"
screenOptions={{
cardStyle: {backgroundColor: '#ffffff'},
headerStyle: {
height: 110,
backgroundColor: '#95a5a6',
borderBottomWidth: 5,
borderBottomColor: '#34495e',
},
headerTitleStyle: { color: '#ffffff', fontSize: 24 },
headerTitleAlign: 'center',
}}
>
</Stack.Navigator>
);
};
모든 플랫폼에서 타이틀을 동일하게 정렬하기 위해서는 headerTitleAlign 속성을 지정한다.
타이틀 컴포넌트 변경
타이틀에 문자열이 아닌 다른 것을 렌더링하기 위해서 headerTitle 속성에 컴포넌트를 반환하는 함수를 지정한다.
- style과 tintColor를 포함한 객체가 파라미터로 전달.
- style : headerTitleStyle에 설정된 값
- tintColor : headerTintColor에 지정된 값
const StackNavigation = () => {
return(
<Stack.Navigator
initialRouteName="Home"
screenOptions={{
...
headerTitleStyle: { color: '#ffffff', fontSize: 24 },
headerTitleAlign: 'center',
headerTitle: ({ style }) => (
<MaterialCommunityIcons name="react" style={style} />
),
}}
- 함수의 파라미터로 전달되는 style을 이용하여 headerTitleStyle에 지정한 스타일과 동일한 스타일이 적용되도록한다.
- 반환되는 컴포넌트는 vector-icons에서 제공하는 컴포넌트를 이용해 리액트 로고가 렌더링되도록 한다.
버튼 수정하기
이전 화면으로 돌아가는 헤더 왼쪽에 있는 버튼을 수정해보자.
<Stack.Screen
name="List"
component={List}
options={{
headerTitle: 'List Screen',
headerBackTitleVisible: true,
headerBackTitle: 'Prev',
}}
/>
- iOS와 안드로이드 플랫폼 버튼 타이틀 렌더링 여부를 동일하게 설정하기 위해 headerBackTitleVisible을 이용할 수 있다.
- 버튼의 타이틀에 이전 화면의 이름이 아닌 다른 값을 이용하고 싶은 경우 headerBackTitle 을 이용한다.
버튼 스타일 수정하기
headerBackTitleStyle을 이용해 버튼 타이틀의 스타일을 지정할 수 있다.
버튼의 타이틀과 이미지 색을 동일하게 변경하려면 headerTintColor를 이용해야 한다.
<Stack.Screen
name="List"
component={List}
options={{
headerTitle: 'List Screen',
headerBackTitleVisible: true,
headerBackTitle: 'Prev',
headerTitleStyle: { fontSize: 24 },
headerTintColor: '#e74c3c',
}}
/>
버튼 컴포넌트 변경
두 플랫폼의 뒤로가기 버튼 아이콘에 동일한 아이콘이 렌더링되도록 하기 위해 headerBackImage에 컴포넌트를 반환하는 함수를 전달해 두 플랫폼이 동일한 이미지를 렌더링하도록 해보자.
<Stack.Screen
name="List"
component={List}
options={{
...
headerBackImage: ({ tintColor }) => {
const style = {
marginRight: 5,
marginLeft: Platform.OS === 'ios'? 11 : 0,
};
return(
<MaterialCommunityIcons
name="keyboard-backspace"
size={30}
color={tintColor}
style={style}
/>
);
},
}}
/>
headerBackImage의 함수 파라미터에 전달되는 tintColor 값을 이용해 아이콘의 색을 지정하고, 두 플랫폼의 버튼 위치를 동일하게 만들기 위해 플랫폼에 따라 스타일을 다르게 적용한다.
- useLayoutEffect Hook 는 컴포넌트가 업데이트 된 직후 화면이 렌더링되기 전에 실행된다.
- headerLeft, headerRight에 각각 컴포넌트를 반환하는 함수를 지정한다.
- navigation에서 제공하는 popToTop 함수는 현재 쌓여있는 모든 화면을 내보내고 첫 화면으로 돌아가는 기능이다.
헤더 감추기
headerMode나 headerShown을 사용하여 헤더를 감춰보자.
headerMode
- float : 헤더가 상단에 유지되며 하나의 헤더를 사용한다.
- screen : 각 화면마다 헤더를 가지며 화면 변경과 함께 나타나거나 사라진다.
- none : 헤더가 렌더링되지 않는다.
<Stack.Screen
name="Home"
component={Home}
ooptions={{ headerShown: false }}
/>
headerShown 은 화면 옵션으로, Navigator 컴포넌트의 screenOptions에 설정하면 전체 화면의 헤더가 보이지 않도록 설정할 수 있다.
3. 탭 내비게이션
- 화면 위나 아래에 위치하며, 탭 버튼을 누르면 버튼과 연결된 화면으로 이동한다.
- 탭 내비게이션을 사용하기 위한 추가 라이브러리를 설치한다.
npm install @react-navigation/bottom-tabs
화면 구성
src/navigations/Tab.js
const Tab = createBottomTabNavigator();
const TabNavigation = () => {
return(
<Tab.Navigator initialRouteName="Settings">
<Tab.Screen name="Mail" component={Mail} />
<Tab.Screen name="Meet" component={Meet} />
<Tab.Screen name="Settings" component={Settings} />
</Tab.Navigator>
);
};
- createBottomTabNavigator 함수를 이용해 탭 내비게이션을 생성
- 탭 바에 있는 버튼 순서는 Navigator 컴포넌트의 자식으로 있는 Screen 컴포넌트의 순서와 동일하다.
- 탭 버튼의 순서를 유지한 채 렌더링되는 첫 화면을 변경하고 싶은 경우 initialRouteName 속성을 이용한다.
탭 바 수정하기
버튼 아이콘 설정
- tabBarIcon을 이용해 탭 버튼에 아이콘을 렌더링한다.
- tabBarIcon에 컴포넌트를 반환하는 함수를 지정하면 버튼의 아이콘이 들어갈 자리에 해당 컴포넌트를 렌더링한다.
const TabIcon = ({ name, size, color }) => {
return <MaterialCommunityIcons name={name} size={size} color={color} />;
};
const Tab = createBottomTabNavigator();
const TabNavigation = () => {
return(
<Tab.Navigator initialRouteName="Settings">
<Tab.Screen
name="Mail"
component={Mail}
options={{
tabBarIcon: props => TabIcon({ ...props, name: 'email '}),
}}
/>
<Tab.Screen
name="Meet"
component={Meet}
options={{
tabBarIcon: props => TabIcon({ ...props, name: 'video' }),
}}
/>
<Tab.Screen
name="Settings"
component={Settings}
options={{
tabBarIcon: props => TabIcon({ ...props, name: 'settings' }),
}}
/>
</Tab.Navigator>
);
};
- 화면을 구성하는 Screen 컴포넌트마다 tabBarIcon에 MaterialCommunityIcons 컴포넌트를 반환하는 함수를 지정한다.
- 만약 Screen 컴포넌트마다 탭 버튼 아이콘을 지정하지 않고 한곳에서 모든 버튼의 아이콘을 관리하고 싶은 경우 Navigator 컴포넌트의 screenOptions 속성을 사용해서 관리할 수 있다.
const TabNavigation = () => {
return(
<Tab.Navigator
initialRouteName="Settings"
screenOptions={({ route }) => ({
tabBarIcon: props => {
let name = '';
if(route.name === 'Mail') name = 'email';
else if (route.name === 'Meet') name = 'video';
else name = 'settings';
return TabIcon({ ...props, name });
},
})}
>
<Tab.Screen name="Mail" component={Mail} />
<Tab.Screen name="Meet" component={Meet} />
<Tab.Screen name="Settings" component={Settings} />
</Tab.Navigator>
);
};
- screenOptions에 객체를 반환하는 함수를 설정하고 함수로 전달되는 route를 이용한다.
라벨 수정
버튼 아래에 렌더링되는 라벨은 Screen 컴포넌트의 name값을 기본값으로 사용한다.
const TabNavigation = () => {
return(
<Tab.Navigator
initialRouteName="Settings"
tabBarOptions={{ labelPosition: 'beside-icon', showLabel: false }}
>
<Tab.Screen
name="Mail"
component={Mail}
options={{
tabBarLabel: 'Inbox',
tabBarIcon: props => TabIcon({ ...props, name: 'email '}),
}}
/>
- 라벨은 tabBarLabel을 이용해 변경할 수 있다.
- labelPosition을 설정하여 라벨을 버튼 아이콘의 아래가 아닌 아이콘 옆에 렌더링되도록 변경할 수 있다.
- showLabel을 이용해 탭 바에서 라벨이 렌더링되지 않도록 설정할 수 있다.
스타일 수정
탭 바의 배경색을 수정해보자.
const TabNavigation = () => {
return (
<Tab.Navigator
initialRouteName="Settings"
tabBarOptions={{
labelPosition: 'beside-icon',
showLabel: false,
style: {
backgroundColor: '#54b7f9',
borderTopColor: '#ffffff',
borderTopWidth: 2,
},
activeTintColor: '#ffffff',
inactiveTintColor: '#cfcfcf',
}}
>
- 탭 바의 스타일은 tabBarOptions 속성에 style의 값으로 스타일 객체를 설정해 변경 가능하다.
- 탭 버튼의 아이콘 색은 각각 activeTintColor와 inactiveTintColor를 이용해 설정 가능하다.
const TabNavigation = () => {
return(
<Tab.Navigator
initialRouteName="Settings"
tabBarOptions={{
labelPosition: 'beside-icon',
showLabel: false,
style: {
backgroundColor: '#54b7f9',
borderTopColor: '#ffffff',
borderTopWidth: 2,
},
activeTintColor: '#ffffff',
inactiveTintColor: '#cfcfcf',
}}
>
<Tab.Screen
name="Mail"
component={Mail}
options={{
tabBarLabel: 'Inbox',
tabBarIcon: props =>
TabIcon({
...props,
name: props.focused ? 'email' : 'email-outline',
}),
}}
/>
...
- 아이콘을 설정하기 위해 파라미터로 size, color, focused를 가진 객체가 전달된다.
- 이 값을 이용해 버튼의 활성화 상태에 따른 다른 버튼을 렌더링하거나 스타일링을 변경한다.
- focused의 값에 따라 버튼이 활성화 되었을 때 내부가 채워진 이미지가 렌더링된다.
- 비활성화 상태에서는 내부가 빈 아이콘이 렌더링된다.
내비게이션은 애플리케이션의 흐름을 관리하기 때문에 애플리케이션을 만들기 전에 어떻게 구성할 지 미리 계획을 세우는 것이 좋다.
리액트 내비게이션에는 여러가지 종류의 내비게이션이 있으므로 다양하게 사용해보고 필요한 기능을 활용하도록 하자.
'dev > React native' 카테고리의 다른 글
[React Native] 채팅 애플리케이션(2) (0) | 2022.01.06 |
---|---|
[React Native] 채팅 애플리케이션 만들기 (0) | 2021.12.26 |
[React Native] Context API (0) | 2021.11.14 |
[React Native] Hooks (0) | 2021.11.12 |
[React Native] 할 일 관리 애플리케이션(2) (0) | 2021.11.06 |