reactnavigation.orgTab navigation 번역 자료입니다. 번역에 문제가 있다면 댓글 달아주시구요. 원문을 보시기를 추천드립니다

아마도 모바일 앱에서 가장 일반적인 네비게이션 스타일은 탭 기반 네비게이션 일 것입니다. 이것은 스크린 하단 또는 헤더 아래 (또는 헤더 대신)에 있는 탭일 수 있습니다.

이 가이드는 createBottomTabNavigator에 대해 설명합니다. createMaterialBottomTabNavigatorcreateMaterialTopTabNavigator를 사용하여 애플리케이션에 탭을 추가 할 수도 있습니다.

계속하기 전에 먼저 @react-navigation/bottom-tabs를 설치하세요 :

npm

npm install @react-navigation/bottom-tabs

yarn

yarn add @react-navigation/bottom-tabs

 

탭 기반(tab-based) 네비게이션의 미니멀 예제

import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

function HomeScreen() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Home!</Text>
    </View>
  );
}

function SettingsScreen() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Settings!</Text>
    </View>
  );
}

const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={HomeScreen} />
        <Tab.Screen name="Settings" component={SettingsScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

Snack 에서 이 예제를 사용해보세요

외관 커스터마이즈

스택 네비게이터를 커스터마이즈하는 방법과 유사합니다 - 탭 네비게이터를 초기화 할 때 설정되는 약간의 프로퍼티와 options에서 스크린별로 커스터마이즈할 수 있는 프로퍼티가 있습니다.

// Expo를 사용하는 경우 @expo/vector-icons에서 Ionicons를 import 하거나 
// 그렇지 않으면 react-native-vector-icons/Ionicons를 import 할 수 있습니다.
import { Ionicons } from '@expo/vector-icons';

// (...)

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator
        screenOptions={({ route }) => ({
          tabBarIcon: ({ focused, color, size }) => {
            let iconName;

            if (route.name === 'Home') {
              iconName = focused
                ? 'ios-information-circle'
                : 'ios-information-circle-outline';
            } else if (route.name === 'Settings') {
              iconName = focused ? 'ios-list-box' : 'ios-list';
            }

            // 여기에 원하는 컴포넌트를 반환 할 수 있습니다!
            return <Ionicons name={iconName} size={size} color={color} />;
          },
        })}
        tabBarOptions={{
          activeTintColor: 'tomato',
          inactiveTintColor: 'gray',
        }}
      >
        <Tab.Screen name="Home" component={HomeScreen} />
        <Tab.Screen name="Settings" component={SettingsScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

Snack 에서 이 예제를 사용해보세요

코드를 자세히 봅시다.

  • tabBarIcon은 하단 탭 네비게이터에서 지원되는 옵션입니다. 스크린 컴포넌트에서 options prop을 사용할 수도 있지만 이 경우 편의를 위해 아이콘 구성을 모아 Tab.NavigatorscreenOptions prop에 넣었습니다.
  • tabBarIconfocused state, colorsize params가 제공되는 함수입니다. 설정을 자세히 살펴보면 tabBarOptionsactiveTintColorinactiveTintColor를 보게됩니다. 기본값은 iOS 플랫폼 기본값이지만 여기에서 변경할 수 있습니다. tabBarIcon에 전달되는 colorfocused state (focused is active)에 따라 활성 또는 비활성 색상입니다. size는 탭바에서 예상되는 아이콘의 크기입니다.
  • createBottomTabNavigator 설정 옵션에 대한 자세한 정보는 전체 API 레퍼런스를 읽으십시오.

아이콘에 배지 추가

때로는 아이콘에 배지를 추가하기를 원합니다. 일반적인 방법은 엑스트라 뷰 컨테이너를 사용하고 절대 위치(absolute positioning)로 배지 요소의 스타일을 지정하는 것입니다.

function IconWithBadge({ name, badgeCount, color, size }) {
  return (
    <View style={{ width: 24, height: 24, margin: 5 }}>
      <Ionicons name={name} size={size} color={color} />
      {badgeCount > 0 && (
        <View
          style={{
            // React Native < 0.57에서는 부모 외부(outside of parent)의 오버플로우가 Android에서 작동하지 않습니다. https://git.io/fhLJ8
            position: 'absolute',
            right: -6,
            top: -3,
            backgroundColor: 'red',
            borderRadius: 6,
            width: 12,
            height: 12,
            justifyContent: 'center',
            alignItems: 'center',
          }}
        >
          <Text style={{ color: 'white', fontSize: 10, fontWeight: 'bold' }}>
            {badgeCount}
          </Text>
        </View>
      )}
    </View>
  );
}

UI 관점에서 이 컴포넌트는 사용할 준비가 되었지만 React Context, Redux, MobX 또는 event emitters를 사용하는 등의 다른 곳에서 배지 수를 올바르게 전달할 수있는 방법을 찾아야합니다.

function HomeIconWithBadge(props) {
  // React Context API, Redux, MobX 또는 event emitters와 같은 다른 방법으로 badgeCount를 전달해야합니다.
  return <IconWithBadge {...props} badgeCount={3} />;
}

Snack 에서 이 예제를 사용해보세요

tabs-badges

탭 간 점프

한 탭에서 다른 탭으로 전환하는 익숙한 API - navigation.navigate.

function HomeScreen({ navigation }) {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Home!</Text>
      <Button
        title="Go to Settings"
        onPress={() => navigation.navigate('Settings')}
      />
    </View>
  );
}

function SettingsScreen({ navigation }) {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Settings!</Text>
      <Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
    </View>
  );
}

Snack 에서 이 예제를 사용해보세요

각 탭의 스택 네비게이터

일반적으로 탭은 하나의 스크린만 표시하지 않습니다. 예를 들어 Twitter 피드에서 트윗을 탭하면 해당 탭 내에서 모든 답글이 포함 된 새 스크린이 나타납니다. 각 탭 내에 별도의 네비게이션 스택이 있다고 생각할 수 있습니다. 이것이 바로 React Navigation의 모델링 방식입니다.

import * as React from 'react';
import { Button, Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

function DetailsScreen() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Details!</Text>
    </View>
  );
}

function HomeScreen({ navigation }) {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Home screen</Text>
      <Button
        title="Go to Details"
        onPress={() => navigation.navigate('Details')}
      />
    </View>
  );
}

function SettingsScreen({ navigation }) {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Settings screen</Text>
      <Button
        title="Go to Details"
        onPress={() => navigation.navigate('Details')}
      />
    </View>
  );
}

const HomeStack = createStackNavigator();

function HomeStackScreen() {
  return (
    <HomeStack.Navigator>
      <HomeStack.Screen name="Home" component={HomeScreen} />
      <HomeStack.Screen name="Details" component={DetailsScreen} />
    </HomeStack.Navigator>
  );
}

const SettingsStack = createStackNavigator();

function SettingsStackScreen() {
  return (
    <SettingsStack.Navigator>
      <SettingsStack.Screen name="Settings" component={SettingsScreen} />
      <SettingsStack.Screen name="Details" component={DetailsScreen} />
    </SettingsStack.Navigator>
  );
}

const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={HomeStackScreen} />
        <Tab.Screen name="Settings" component={SettingsStackScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

Snack 에서 이 예제를 사용해보세요

왜 TabBarIOS 나 다른 컴포넌트 대신 TabNavigator가 필요합니까?

스탠드얼론 탭바 컴포넌트를 앱에서 사용하는 네비게이션 라이브러리에 통합하지 않고 사용하려고 시도하는 것이 일반적일 겁니다. 어떤 경우에는 이것이 잘 작동합니다! 그러나 이렇게하면 예상치 못한 문제가 발생할 수 있음을 경고해야합니다.

예를 들어, React Navigation의 탭 네비게이터는 Android back button을 처리하지만 스탠드얼론 컴포넌트는 일반적으로 처리하지 않습니다. 또한 두 개의 고유한 API를 호출해야하는 경우 (개발자로서) “이 탭으로 이동한 다음 이 화면으로 이동”과 같은 조치를 수행하기가 더 어렵습니다. 마지막으로, 모바일 유저 인터페이스에는 특정 컴포넌트가 다른 컴포넌트의 레이아웃 또는 존재를 인식해야 하는 수많은 작은 디자인 디테일이 있습니다. - 예를 들어, 반투명 탭바가 있는 경우 컨텐츠가 그 아래에서 스크롤되고 스크롤뷰의 맨 아래에 탭바의 높이와 동일한 삽입이 있어야 모든 컨텐츠를 볼 수 있습니다. 탭 표시 줄을 두 번 누르면 활성 네비게이션 스택이 스택의 상단으로 튀어 나와야(pop)하고 다시 수행하면 해당 스택의 활성 스크롤뷰가 맨 위로 스크롤됩니다. 이러한 모든 동작이 React Navigation으로 아직 구현되지는 않았지만 스탠드얼론 탭뷰 컴포넌트를 사용하면 이 중 아무것도 실행되지 않습니다.

탭 네비게이터에는 스택이 포함되어 있고 특정 스크린에서 탭바를 숨기려 합니다.

여기의 문서를 보세요