Jetpack Navigation + BottomNavigationBar 구현하기

1. Jetpack Navigation


사실 Jetpack Navigation에 대해서는 이전에도 한번 포스트를 쓴 적이 있다.

Navigation은 크게 3가지 요소로 이루어져 있다.


NavController

- 대상(즉, 앱의 화면) 간 이동을 담당하는데, 탐색 동작을 처리하는 역할

- 대상을 탐색하고 딥 링크를 처리하며 대상 백 스택을 관리하는 등의 여러 메소드를 제공


NavGraph

- 이동할 컴포저블 대상의 매핑을 담당

- 앱 내의 화면 연결을 보여주는 일종의 지도 역할을 한다.


NavHost

- 현재 탐색 대상(navigation destination)이 포함된 UI 요소

- NavGraph의 현재 대상을 표시하는 컨테이너 역할을 하는 컴포저블


2. BottomNavigationBar 구현하기

이제 위에서 설명한 Navigation과 Compose를 활용해 BottomNavigationBar를 구현해보자.

gradle에 라이브러리 추가

dependencies {
    implementation("androidx.navigation:navigation-compose:2.7.7")
}


Bottom Navigation으로 이동할 화면 생성

필자는 여기서 Home, Rating, Profile 3개의 화면을 만들어주었다.


@Composable
fun HomeScreen() {
    Text(text = "Home")
}

@Composable
fun RatingScreen() {
    Text(text = "Rating")
}

@Composable
fun ProfileScreen() {
    Text(text = "Profile")
}


BottomNavItem 생성.

Bottom Navigation으로 이동할 item 객체 클래스 BottomNavItem 클래스를 생성하고,

그 자식으로 Home, Rating, Profile 을 추가한다.

sealed class BottomNavItem(
    @StringRes val title: Int,
    @DrawableRes val icon: Int,
    val screenRoute: String
) {
    object Home : BottomNavItem(R.string.home, R.drawable.ic_home, NavScreens.Home.name)
    object Rating : BottomNavItem(R.string.rating, R.drawable.ic_rating, NavScreens.Rating.name)
    object Profile : BottomNavItem(R.string.profile, R.drawable.ic_profile, NavScreens.Profile.name)
}


NavHost, NavGraph 생성.

NavHost 함수의 NavGraphBuilder 를 통해서 NavGraph를 생성할 수 있다.

@Composable
private fun MyNavHost(
    modifier: Modifier = Modifier,
    navController: NavHostController,
    startDestination: String
) {
    NavHost(
        modifier = modifier,
        navController = navController,
        startDestination = startDestination
    ) {
        ...

        composable(route = NavScreens.Home.name) {
            HomeScreen(
                onSearchClicked = { navController.navigate(NavScreens.Search.name) }
            )
        }

        composable(route = NavScreens.Rating.name) {
            RatingScreen()
        }

        composable(route = NavScreens.Profile.name) {
            ProfileScreen()
        }

        composable(route = NavScreens.Search.name) {
            SearchScreen()
        }
    }
}


Bottom Navigation 생성
@Composable
private fun MyBottomNavigation(
    modifier: Modifier = Modifier,
    navController: NavHostController
) {
    val navBackStackEntry by navController.currentBackStackEntryAsState()
    val currentRoute = navBackStackEntry?.destination?.route
    val items = listOf(
        BottomNavItem.Home,
        BottomNavItem.Rating,
        BottomNavItem.Profile
    )

    NavigationBar {
        items.forEach { item ->
            NavigationBarItem(
                selected = currentRoute == item.screenRoute,
                label = {
                    Text(
                        text = stringResource(id = item.title),
                        style = TextStyle(
                            fontSize = 12.sp
                        )
                    )
                },
                icon = {
                    Icon(
                        painter = painterResource(id = item.icon),
                        contentDescription = stringResource(id = item.title)
                    )
                },
                onClick = {
                    navController.navigate(item.screenRoute) {
                        navController.graph.startDestinationRoute?.let {
                            popUpTo(it) { saveState = true }
                        }
                        launchSingleTop = true
                        restoreState = true
                    }
                },
            )
        }
    }

}


BottomNavigationBar를 그리는 앱 화면 구성

@Composable
fun MyApp() {
    val navController = rememberNavController()

    Scaffold(
        modifier = Modifier.fillMaxSize(),
        topBar = {
            ...
        },
        bottomBar = {
            MyBottomNavigation(navController = navController)
        }
    ) {
        Box(modifier = Modifier.padding(it)) {
            MyNavHost(
                navController = navController,
                startDestination = NavScreens.Home.name
            )
        }
    }
}



댓글

이 블로그의 인기 게시물

Jetpack Compose Navigation 정리

아이랑스토리 어플리케이션 개인정보처리방침

Android WebView WebViewClient (웹뷰에서 일어나는 요청, 상태, 에러 등 다양한 상황) 재정의 사용