간단한 Jetpack Compose 탐색 예제

Jetpack Compose의 다양한 화면과 화면 간 탐색 방법을 표시하는 간단한 앱입니다.

이 기사는 원래 2022년 4월 23일 vtsen.hashnode.dev에 게시되었습니다.

Jetpack Compose에서 navigation component을 사용해 보기 위해 이 간단한 앱을 만들었습니다. 이것이 앱의 모습입니다.



다음은 이 간단한 앱을 구현하는 단계입니다.

1. 내비게이션 작성 라이브러리 추가


app\build.gradle에서 이 종속성을 추가합니다.

dependencies {
    implementation "androidx.navigation:navigation-compose:2.5.0-alpha01"
}


2. NavHostController 생성


NavHostController는 다음 단계에서 다른 화면으로 이동하는 데 사용되는 탐색 그래프를 빌드하는 데 필요합니다.

루트 구성 가능 함수에서 NavHostController를 사용하여 이 rememberNavController()를 생성하고 이를 BuildNavGraph() 구성 가능 함수에 전달합니다.

@Composable
private fun MainScreen() {
    SimpleNavComposeAppTheme {
        val navController = rememberNavController()
        BuildNavGraph(navController)
    }
}


3. 내비게이션 그래프 구축



탐색 그래프는 다음과 같습니다.
  • 로그인 화면 -> 홈 화면 -> 프로필 화면
  • 로그인 화면 -> 홈 화면 -> 검색 화면

  • 로그인 화면이 시작 대상입니다. 홈 화면에는 탐색 인수가 없습니다. 프로필 화면은 2개의 탐색 인수를 사용하고 검색 화면은 1개의 탐색 인수를 사용합니다.

    탐색 그래프를 빌드하려면 NavHost() 구성 가능 함수와 NavGraphBuilder.composable() 함수를 사용하여 구성 가능한 각 화면을 빌드합니다.

    fun BuildNavGraph(navController: NavHostController) {
        NavHost(
            navController = navController,
            startDestination = "login"
        ) {
            composable(route = "login") {
                //call LoginScreen composable function here
            }
    
            composable(route = "home") {
                //call HomeScreen composable function here
            }
            ...
        }
    }
    
    


    홈 화면으로 이동하려면:

    navController.navigate("home")
    


    현재 스택을 되돌리려면:

    navController.popBackStack()
    


    로그인 화면에 팝업하려면:

    navController.popBackStack(NavRoute.Login.path, inclusive = false)
    


    인수를 사용한 탐색


    navGraphBuilder.composable에는 routearguments라는 두 개의 매개변수가 있습니다. 인수가 있는 탐색을 위해 routearguments 매개변수를 모두 업데이트하려고 합니다.

    프로필 화면의 경로 형식입니다. id는 첫 번째 매개변수입니다. showDetails는 두 번째 매개변수입니다.

    route = "profile/{id}/{showDetails}"
    

    arguments 매개변수는 다음과 같습니다.

    arguments = listOf(
        navArgument("id") {
            type = NavType.IntType
        }
        ,
        navArgument("showDetails") {
            type = NavType.BoolType
        }
    )
    


    파라미터의 NavType를 지정할 수 있습니다. defaultValue를 설정하여 인수를 선택 사항으로 만들 수도 있습니다.

    ...
        navArgument("showDetails") {
            type = NavType.BoolType
            defaultValue = false
        }
    ...
    


    I personally will avoid using defautValue because it requires your route to follow certain format (i.e. "profile/{id}/?showDetails={showDetails}"). ?showDetails is the optional arguement to allow you specify the defaultValue.



    인수 값을 검색하려면 NavBackStackEntry.arguments를 사용합니다.

    composable(
       ...
    ) { navBackStackEntry ->
    
        val args = navBackStackEntry.arguments
    
        // get id param value
        val id = args?.getInt("id")!!
        // get showDetails param value
        val showDetails = args?.getBoolean("showDetails")!!
    
        // call profile screen composable function here
        ...
    }
    


    프로필 화면으로 이동하는 예시입니다.

    val id = 7
    val showDetails = true
    navController.navigate("profile/$id/$showDetails")
    


    모든 경로 형식이 좋습니다!



    이것을 사용하는 대신(가장 간단한 형식이기 때문에 선호합니다):

    route = "profile/{id}/{showDetails}"
    


    다음을 사용할 수 있습니다(선택 사항showDetails을 원하는 경우 필수):

    route = "profile/{id}/?showDetails={showDetails}"
    


    또는 다음과 같습니다(idshowDetails를 모두 선택적으로 사용하려는 경우 필수):

    route = "profile/?id={id}/?showDetails={showDetails}"
    


    그러나 다음을 사용하지 마십시오.

    route = "profile/{id}{showDetails}"
    


    Please make sure you at least put a separator (any string) between the navigation parameters. This navigation parameters could be parsed wrongly especially they're same data type.



    경로 형식을 변경하면 내비게이션 호출도 업데이트해야 합니다. 예를 들어:

    val id = 7 
    val showDetails = true
    navController.navigate("profile/$id/?showDetails=$showDetails")
    


    너무 많은 상용구 코드



    하드 코딩된 문자열이 어디에나 있다는 것을 눈치채셨을 것입니다. 한 번의 실수로 앱이 다운될 수 있습니다. 오류가 발생하기 쉽습니다.

    그래서 내가 한 일은 거기에 모든 하드 코딩된 문자열이 있는 이 클래스NavRoute를 만드는 것입니다. 또한 유틸리티 기능(즉, 탐색 경로를 빌드하기 위한 withArgs()withArgsFormat() 형식 문자열을 빌드하기 위한 route도 포함합니다.

    sealed class NavRoute(val path: String) {
    
        object Login: NavRoute("login")
    
        object Home: NavRoute("home")
    
        object Profile: NavRoute("profile") {
            val id = "id"
            val showDetails = "showDetails"
        }
    
        object Search: NavRoute("search") {
            val query = "query"
        }
    
        // build navigation path (for screen navigation)
        fun withArgs(vararg args: String): String {
            return buildString {
                append(path)
                args.forEach{ arg ->
                    append("/$arg")
                }
            }
        }
    
        // build and setup route format (in navigation graph)
        fun withArgsFormat(vararg args: String) : String {
            return buildString {
                append(path)
                args.forEach{ arg ->
                    append("/{$arg}")
                }
            }
        }
    }
    


    일부 사용 예:

    // navigate to home
    navController.navigate(NavRoute.Home.path)
    
    // navigate to search
    navController.navigate(NavRoute.Search.withArgs(query))
    
    // setup route for search screen with query param
    route = NavRoute.Search.withArgsFormat(NavRoute.Search.query)
    


    마지막 생각들



    위의 NavRoute approach이 좋은 것인지 잘 모르겠습니다. 코드를 읽을 수 없게 만드는지 확실하지 않습니까? 어쩌면 조금? 그러나 적어도 많은 하드 코딩된 문자열을 제거하고 더 이상 상용구 코드를 제거할 수는 없습니다.

    더 많은 상용구 코드를 제거하는 Compose Destinations 라이브러리가 있습니다. 이 라이브러리를 사용하기 전에 기본을 먼저 이해하는 것이 더 낫다고 생각합니다.

    이 라이브러리를 사용하도록 이 앱을 변환하는 단계는 다음과 같습니다.
  • Compose Destinations - Navigation Library

  • 소스 코드



    GitHub 저장소: Demo_SimpleNavigationCompose


    또한보십시오


  • How to Add Bottom Navigation in Jetpack Compose?
  • How to Add Navigation Drawer in Jetpack Compose?
  • Android Development Tips and Tricks
  • 좋은 웹페이지 즐겨찾기