0Pricing
Android Academy · 강의

하단 탐색과 탭

NavController에 연결된 BottomNavigationView로 여러 섹션의 탐색을 구현하고 TabLayout, ViewPager2, TabLayoutMediator로 스와이프 가능한 탭을 만듭니다.

하단 탐색과 탭은(는) CoddyKit의 무료 Android Academy 강의입니다. 이것은 5개 중 5번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Android Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Android Academy 강의에는 총 5개의 강의가 포함되어 있습니다.

탐색 패턴

Android 앱의 최상위 탐색에 사용하는 일반적인 두 가지 패턴입니다:

  • 하단 탐색 — 3~5개의 주요 목적지에 사용합니다. 항상 표시됩니다. 중요도가 같은 섹션(예: 홈, 검색, 프로필)에 가장 적합합니다.
  • 탭 — 한 화면 안에서 서로 관련된 콘텐츠를 표시할 때 사용합니다(예: 전체 / 활성 / 완료). 스와이프를 지원하기 위해 ViewPager2와 함께 사용하는 경우가 많습니다.

BottomNavigationView 레이아웃

Activity 레이아웃에 BottomNavigationView와 FragmentContainerView를 추가합니다:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/navHostFragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        app:navGraph="@navigation/nav_graph"
        app:defaultNavHost="true" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottomNav"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:menu="@menu/bottom_nav_menu" />

</LinearLayout>

하단 탐색 메뉴 항목

res/menu/bottom_nav_menu.xml에서 항목을 정의합니다. 각 항목의 ID는 탐색 그래프 목적지의 ID와 일치해야 합니다:

<!-- res/menu/bottom_nav_menu.xml -->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/homeFragment"
        android:icon="@drawable/ic_home"
        android:title="Home" />
    <item
        android:id="@+id/searchFragment"
        android:icon="@drawable/ic_search"
        android:title="Search" />
    <item
        android:id="@+id/profileFragment"
        android:icon="@drawable/ic_person"
        android:title="Profile" />
</menu>

NavController에 연결하기

onCreate()에서 BottomNavigationView를 NavController에 연결합니다:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val navHost = supportFragmentManager
            .findFragmentById(R.id.navHostFragment) as NavHostFragment
        val navController = navHost.navController

        binding.bottomNav.setupWithNavController(navController)

        // Hide bottom nav on detail screens:
        navController.addOnDestinationChangedListener { _, destination, _ ->
            binding.bottomNav.visibility = when (destination.id) {
                R.id.detailFragment -> View.GONE
                else -> View.VISIBLE
            }
        }
    }
}

하단 탐색에 배지 표시하기

하단 탐색 항목에 알림 배지를 표시합니다:

// Show a numbered badge:
val badge = binding.bottomNav.getOrCreateBadge(R.id.homeFragment)
badge.number = 5
badge.isVisible = true

// Show dot badge (no number):
val dotBadge = binding.bottomNav.getOrCreateBadge(R.id.searchFragment)
dotBadge.isVisible = true

// Remove badge:
binding.bottomNav.removeBadge(R.id.homeFragment)

TabLayout

TabLayout은 가로 탭을 표시하며, 일반적으로 스와이프할 수 있는 콘텐츠를 위해 ViewPager2와 함께 사용합니다:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

</LinearLayout>

ViewPager2 + FragmentStateAdapter

각 탭 위치에 해당하는 프래그먼트를 제공하는 어댑터를 만듭니다:

class TasksPagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {

    override fun getItemCount() = 3

    override fun createFragment(position: Int): Fragment = when (position) {
        0 -> AllTasksFragment()
        1 -> ActiveTasksFragment()
        2 -> CompletedTasksFragment()
        else -> throw IllegalStateException("Unknown tab $position")
    }
}

TabLayoutMediator

TabLayoutMediator를 사용해 ViewPager2와 TabLayout을 연결합니다:

// In Fragment.onViewCreated():
val adapter = TasksPagerAdapter(this)
binding.viewPager.adapter = adapter

TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
    tab.text = when (position) {
        0 -> "All"
        1 -> "Active"
        2 -> "Done"
        else -> ""
    }
}.attach()

// Disable swipe if needed:
binding.viewPager.isUserInputEnabled = false

아이콘이 있는 탭

TabLayout 탭에 아이콘을 추가합니다:

TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
    when (position) {
        0 -> {
            tab.text = "Home"
            tab.setIcon(R.drawable.ic_home)
        }
        1 -> {
            tab.text = "Search"
            tab.setIcon(R.drawable.ic_search)
        }
        2 -> {
            tab.text = "Profile"
            tab.setIcon(R.drawable.ic_person)
        }
    }
}.attach()

오프스크린 페이지 제한

기본적으로 ViewPager2는 인접한 페이지만 메모리에 유지합니다. 탭을 전환할 때도 탭이 유지되어야 한다면 offscreenPageLimit을 늘리세요:

// Keep 2 pages on each side alive:
binding.viewPager.offscreenPageLimit = 2

// Note: FragmentStateAdapter saves and restores state for off-screen
// fragments even when offscreenPageLimit is 1 (default).
// Only increase this when you need views (not just state) to survive.

하단 탐색과 탭 비교: 선택하기

적절한 패턴을 선택하기 위한 간단한 안내입니다:

  • 하단 탐색 사용: 목적이 서로 다른 최상위 목적지가 3~5개일 때(홈, 검색, 알림, 프로필)
  • 탭 사용: 같은 유형의 콘텐츠를 필터링하거나 분류할 때(전체 / 활성 / 보관된 작업)
  • 둘 다 사용: 최상위 섹션에는 하단 탐색을 사용하고, 섹션 내부의 하위 필터에는 탭을 사용합니다

빠른 확인

TabLayout을 ViewPager2에 연결하고 탭 레이블을 설정하는 클래스는 무엇인가요?

복습: 하단 탐색과 탭

여러 섹션을 올바르게 탐색하는 방법입니다:

  • BottomNavigationView — 중요도가 같은 3~5개의 목적지에 사용하며, 메뉴 ID는 탐색 그래프 목적지 ID와 일치해야 합니다
  • setupWithNavController() — 탭 전환과 백 스택을 자동으로 처리합니다
  • getOrCreateBadge()를 사용한 배지
  • TabLayout + ViewPager2 — 같은 콘텐츠를 스와이프하며 필터링된 화면으로 표시합니다
  • TabLayoutMediator — 두 요소를 연결하고 레이블을 설정합니다

다음: 코드를 안정적으로 유지하기 위한 JUnit 단위 테스트입니다.

자주 묻는 질문

“하단 탐색과 탭” 강의는 무료인가요?

네 — “하단 탐색과 탭” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Android Academy 강의 전체를 잠금 해제할 수 있습니다. Android Academy 강의에는 총 5개의 강의가 포함되어 있습니다.

“하단 탐색과 탭”에서 뭘 배우나요?

NavController에 연결된 BottomNavigationView로 여러 섹션의 탐색을 구현하고 TabLayout, ViewPager2, TabLayoutMediator로 스와이프 가능한 탭을 만듭니다. 브라우저에서 직접 실행하는 실습 코드로 Android Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Android Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Android Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 5개 중 5번째 강의입니다.

“하단 탐색과 탭” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Android Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Android Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. Material Design 기초
  2. 테마와 스타일
  3. 사용자 지정 뷰
  4. 애니메이션과 전환
  5. 하단 탐색과 탭
← Android Academy(으)로 돌아가기