Jetpack Compose : Navigation

aram·2021년 10월 30일
0

Library 적용

implementation 'androidx.navigation:navigation-compose:2.4.0-alpha08'

사용하기

1. NavHost

composable() 메소드로 시작 경로와 라우트를 정의한다.

val navController = rememberNavController()

NavHost(navController = navController, startDestination = "home") {
    composable(route = "home") { Home() }
    composable(route = "search") { Search() }
}
@Composable
fun Home(navController: NavController) {
    Button(onClick = { navController.navigate("search") }) {
        Text(text = "Click")
    } 
}

3. With Argument

'slug' 라는 string 타입의 argument 를 사용하여 HomeDetail로 이동하는 예제

NavHost(startDestination = "home/{slug}") {
    composable(
        "home/{slug}",
        arguments = listOf(navArgument("slug") { type = NavType.StringType })
    ) { backStackEntry ->
        val slug = requireNotNull(backStackEntry.arguments).getString("slug")
        HomeDetail(navController, slug)
    }
}

4. Nested Navigation

BottomBar() 의 네비게이션과 상세 화면으로 이동하기 위한 예제.
네비게이션 규모가 커질수록 NavGraphBuilder() 로 중첩 네비게이션을 쓰는게 좋다.

sealed class 만들기

sealed class NavItem(
    @StringRes val title: Int,
    val icon: ImageVector,
    val route: String
){
    object Hospital : NavItem(R.string.nav_hospital, Icons.Filled.LocalHospital, "hospital")
    object Article : NavItem(R.string.nav_article, Icons.Filled.Article, "article")
}

addHomeGraph

fun NavGraphBuilder.addHomeGraph(
    navController: NavHostController,
    onClickHospital: (String, NavBackStackEntry) -> Unit,
    onClickArticle: (String, NavBackStackEntry) -> Unit
) {
    composable(NavItem.Hospital.route) {
        Hospitals(navController, onClick = { slug ->
            onClickHospital(slug, it)
        })
    }
    composable(NavItem.Article.route) {
        Article(navController, onClick = { slug ->
            onClickArticle(slug, it)
        })
    }
}

mainNavGraph

fun NavGraphBuilder.mainNavGraph(
    navController: NavHostController,
    onClickHospital: (String, NavBackStackEntry) -> Unit,
    onClickArticle: (String, NavBackStackEntry) -> Unit
) {
    navigation(
        route = "home",
        startDestination = NavItem.Hospital.route
    ) {
        addHomeGraph(navController, onClickHospital, onClickDoctor, onClickDeal, onClickArticle)
    }

    composable(
        "hospital_detail/{slug}",
        arguments = listOf(navArgument("slug") { type = NavType.StringType })
    ) { backStackEntry ->
        val slug = requireNotNull(backStackEntry.arguments).getString("slug")
        HospitalDetail(navController, slug)
    }

    composable(
        "article_detail/{slug}",
        arguments = listOf(navArgument("slug") { type = NavType.StringType })
    ) { backStackEntry ->
        val slug = requireNotNull(backStackEntry.arguments).getString("slug")
        ArticleDetail(navController, slug)
    }
}

View

@Composable
fun MainContent() {
    val navController = rememberNavController()
    val navBackStackEntry by appState.navController.currentBackStackEntryAsState()
    val currentRoute = navBackStackEntry?.destination?.route?.substringBeforeLast("/")

    Scaffold(
        topBar = { TopBar(navController) },
        bottomBar = { BottomBar(navController) },
        floatingActionButton = { FloatingChatButton() }
    ) {
        NavHost(navController = navController, startDestination = "home") {
            mainNavGraph(
                navController = navController,
                onClickHospital = {navController.navigate("hospital_detail/$slug")},
                onClickArticle = {navController.navigate("article_detail/$slug")}
            )
        }
    }
}

Detail Page

@Composable
fun HospitalDetail(
    navController: NavHostController, slug: String
) {
    val viewModel: HospitalVM = viewModel()
    val hospital = viewModel.hospital.observeAsState().value
    val loadingState = viewModel.loading.observeAsState().value

    LaunchedEffect(key1 = "GET_HOSPITAL_DETAIL") {
        slug?.let {
            viewModel.fetchHospitalItem(slug)
        }
    }

    if (loadingState == true) {
        LoadingBar()
    } else {
        hospital?.let {
            HospitalDetailView(hospital)
        }
    }
}

참고
https://developer.android.com/jetpack/compose/navigation#bottom-nav
https://github.com/android/compose-samples/tree/main/Jetsnack

0개의 댓글