(Android/Navigation) Navigation Component — Bottom Navigation 연동


1. 구조

바텀 내비게이션의 각 탭을 NavGraph의 최상위 Destination으로 연결합니다.

BottomNavigationView
   ├─ 홈   → homeFragment
   ├─ 검색 → searchFragment
   └─ 설정 → settingsFragment
        (NavController가 선택에 맞춰 화면 전환)

2. 메뉴와 그래프 연결 규칙

메뉴 아이템의 ID를 그래프 Destination 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="홈" />
    <item android:id="@+id/searchFragment"
        android:icon="@drawable/ic_search" android:title="검색" />
    <item android:id="@+id/settingsFragment"
        android:icon="@drawable/ic_settings" android:title="설정" />
</menu>
<!-- nav_graph.xml: 위 메뉴 ID와 같은 id의 fragment 선언 -->
<fragment android:id="@+id/homeFragment" ... />
<fragment android:id="@+id/searchFragment" ... />
<fragment android:id="@+id/settingsFragment" ... />

3. 코드 연동

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

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

        // 한 줄 연결: 탭 선택 시 이동 + 화면 이동 시 탭 선택 상태 동기화
        binding.bottomNav.setupWithNavController(navController)

        // 탭 화면들은 모두 최상위로 취급 (뒤로 가기 화살표 숨김)
        val appBarConfiguration = AppBarConfiguration(
            setOf(R.id.homeFragment, R.id.searchFragment, R.id.settingsFragment)
        )
        setupActionBarWithNavController(navController, appBarConfiguration)
    }
}

4. 탭별 백스택 보존

setupWithNavController는 기본적으로 탭 전환 시 각 탭의 상태를 저장/복원합니다 (saveState/restoreState).

홈 탭 → 상세 화면 이동 → 검색 탭 → 다시 홈 탭
   ↓
홈 탭의 상세 화면이 그대로 복원됨

직접 이동을 구현한다면 동일한 옵션을 줘야 합니다.

navController.navigate(R.id.searchFragment, null, navOptions {
    popUpTo(navController.graph.startDestinationId) { saveState = true }
    launchSingleTop = true
    restoreState = true
})

탭 재선택(이미 선택된 탭을 다시 누름) 동작은 setOnItemReselectedListener로 별도 처리합니다 (예: 맨 위로 스크롤).


5. 하위 화면에서 바텀바 숨기기

상세 화면 등에서는 바텀바가 보이지 않는 것이 자연스럽습니다.

val topLevelDestinations = setOf(
    R.id.homeFragment, R.id.searchFragment, R.id.settingsFragment
)

navController.addOnDestinationChangedListener { _, destination, _ ->
    // 최상위 탭 화면에서만 바텀바 표시
    binding.bottomNav.isVisible = destination.id in topLevelDestinations
}

6. 정리



Related Posts