🤖 Compose

[Compose] Navigation

콩드로이드 2025. 1. 22. 18:47

라이브러리 추가가 필요합니다 

[libs.version.toml]

[versions]
//...
navigationVersion = "2.8.5"

[libraries]
//...
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationVersion" }

 

[build.gradle]

implementation(libs.androidx.navigation.compose)

 


Navigation은 화면 간 전환을 관리하는 중요한 요소입니다

예제를 통해 각각 필요한 개념을 익혀보겠습니다 

 

 

NavController

- 현재 Navigation 상태 관리, 화면 간 이동을 처리
- 각 스크린에서 NavController를 인자로 받아 사용 가능

navController를 받는 Composable 함수를 생성합니다 

@Composable
fun NavTest(
    modifier: Modifier = Modifier,
    navController : NavHostController = rememberNavController()
)

 

 

NavHost를 생성합니다 

- Navigation 그래프를 정의하는 컨테이너, startDestination을 지정하여 처음 표시될 화면 설정

    NavHost(
        navController = navController,
        startDestination = "Korea",
        modifier = modifier
    ) {
        composable("Korea") {

            Column {
                Text("한국이에요 🇰🇷")
                Spacer(modifier = Modifier.size(10.dp))
                Button(onClick = {
                    navController.navigate("Korea") {
                        launchSingleTop = true
                    }
                }) {
                    Text(text = "한국으로 이동")
                }

                Button(onClick = {
                    navController.navigate("America")
                }) {
                    Text(text = "미국으로 이동")
                }
                Button(onClick = {
                    navController.navigate("Japan")
                }) {
                    Text(text = "일본으로 이동")
                }

                Button(onClick = {
                    navController.navigate("Argument/Mexico")
                }) {
                    Text(text = "멕시코로 이동")
                }
            }
        }

 

startDestination을 설정하는 NavHost를 만들었고, NavHost 내부 즉 NavBackStackEntry에 composable을 추가합니다 

각 화면은 composable 함수로 정의되고 compose은 NavHostBuilder의 composable로 아래의 paramater들을 가질 수 있습니다

 

위의 예제에선 route를 "Korea"으로 설정합니다

 

여러 화면을 왔다갔다 하는 예제를 보면 아래와 같습니다 

@Composable
fun NavTest(
    modifier: Modifier = Modifier,
    navController : NavHostController = rememberNavController()
) {
    NavHost(
        navController = navController,
        startDestination = "Korea",
        modifier = modifier
    ) {
        composable("Korea") {

            Column {
                Text("한국이에요 🇰🇷")
                Spacer(modifier = Modifier.size(10.dp))
                Button(onClick = {
                    navController.navigate("Korea") {
                        launchSingleTop = true
                    }
                }) {
                    Text(text = "한국으로 이동")
                }

                Button(onClick = {
                    navController.navigate("America")
                }) {
                    Text(text = "미국으로 이동")
                }
                Button(onClick = {
                    navController.navigate("Japan")
                }) {
                    Text(text = "일본으로 이동")
                }

                Button(onClick = {
                    navController.navigate("Argument/Mexico")
                }) {
                    Text(text = "멕시코로 이동")
                }
            }
        }

        composable("America") {
            Column {
                Text("미국입니다  🇺🇸")
                Button(onClick = {
                    navController.navigate("Korea")
                }) {
                    Text(text = "한국으로 이동")
                }
                Button(onClick = {
                    navController.navigate("Japan")
                }) {
                    Text(text = "일본으로 이동")
                }
            }
        }


        composable("Japan") {
            Column {
                Text("일본입니다 🇯🇵")
                Button(onClick = {
                    navController.navigate("Korea")
                }) {
                    Text(text = "한국으로 이동")
                }
            }
        }

        composable("Argument/{countryName}") { navBackStackEntry ->
            val countryName = navBackStackEntry.arguments?.getString("countryName")
            Text("Argument/$countryName")
            Button({
                navController.navigate("Argument/Mexico")
            }) {
                Text("Argument/Mexico로 이동")
            }
        }

        composable("Argument/Mexico") {
            Text("멕시코입니다 🇲🇽")
        }
    }
}

 

 

navigate의 인자로는 다양하게 들어갈 수 있어요 

destination (String) : ex) "Korea", "America"
args (Bundle?) : ex) navController.navigate("Argument/$countryName")와 같이 사용
options (NavOptions?) : NavOptions 객체를 통해 애니메이션, 화면 전환 방식 등을 설정 가능

val navOptions = NavOptions.Builder()
                .setEnterAnim(R.anim.slide_in_right)  // 진입 애니메이션
                .setExitAnim(R.anim.slide_out_left)    // 퇴장 애니메이션
                .setPopEnterAnim(R.anim.slide_in_left)  // 뒤로 가기 시 진입 애니메이션
                .setPopExitAnim(R.anim.slide_out_right)  // 뒤로 가기 시 퇴장 애니메이션
                .build()
                
navController.navigate("detail", navOptions)

 

builder (NavOptionsBuilder.() -> Unit) 

 Button(onClick = {
            navController.navigate("Japan") {
                // NavOptionsBuilder를 사용하여 네비게이션 옵션 설정
                launchSingleTop = true // 이미 존재하는 화면으로 이동할 때 중복 생성 방지
                restoreState = true // 이전 상태 복원
                popUpTo("Korea") {
                    inclusive = true 
                }
            }
        }) {
            Text("한국으로 이동")
        }

 

이런식으로 다양한 옵션을 설정할 수 있습니다 

launchSingleTop은 기존 안드로이드에서의 개념과 똑같아요 

popUpTo는 현재 스택에서 지정한 목적지(destination)까지의 모든 화면을 제거

만약 Korea -> Japan -> Mexico -> Korea의 스택일 때 popUpTo("Korea")를 하면 빈 스택이 됩니다.

inclusive는 popUpTo와 함께 사용되는데, popUpTo에서 화면을 제거할 때 특정 목적지 화면을 포함할지 여부를 결정

inclusive가 true로 설정되면, 지정한 목적지 화면도 스택에서 제거됩니다. 기본값은 false이구요

 

만약 Korea -> Japan -> Mexico -> Korea의 스택일 때 popUpTo("Korea") { inclusive = false } 를 하게 되면 

"Korea"까지의 모든 화면이 제거되지만, "Korea" 자체는 포함되지 않으므로 남게 됩니다

 


궁금하신 점이나 의견이 있으시면 댓글 부탁드립니다 감사합니다 😊

'🤖 Compose' 카테고리의 다른 글

[Compose] 단방향 데이터 흐름  (0) 2025.01.23
[Compose] Theme  (0) 2025.01.22
[Compose] compositionLocal  (0) 2025.01.21
[Compose] viewModel , LiveData  (0) 2025.01.21
[Compose] Compose 주의점  (0) 2025.01.17