탐색에 필요한 종속성
dependencies {
val nav_version = "2.7.7"
// Java language implementation
implementation("androidx.navigation:navigation-fragment:$nav_version")
implementation("androidx.navigation:navigation-ui:$nav_version")
// Kotlin
implementation("androidx.navigation:navigation-fragment-ktx:$nav_version")
implementation("androidx.navigation:navigation-ui-ktx:$nav_version")
// Feature module Support
implementation("androidx.navigation:navigation-dynamic-features-fragment:$nav_version")
// Testing Navigation
androidTestImplementation("androidx.navigation:navigation-testing:$nav_version")
// Jetpack Compose Integration
implementation("androidx.navigation:navigation-compose:$nav_version")
}
https://developer.android.com/guide/navigation/navcontroller?hl=ko
val navController = rememberNavController()
컴포저블 계층 구조에서 높은 수준의 NavController를 만들어야 한다. 이 값은 이를 참조해야 하는 모든 컴포저블이 할 수 있을 만큼 충분히 높아야 한다.
이렇게 하면 NavController를 화면 외부에서 컴포저블을 업데이트하기 위한 단일 정보 소스로 사용할 수 있다. 이는 상태 호이스팅의 원칙을 따른다.
참고로 뷰 UI 프레임워크를 사용하는 경우, 컨텍스트에 따라 다음과 같이 NavController를 검색할 수 있다.
(일반적으로 먼저 NavHostFragment를 가져온 다음 프래그먼트에서 NavController를 검색함)
Fragment.findNavController()
View.findNavController()
Activity.findNavController(viewId: Int)
// 예시코드
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
Destination 에는 세 가지 일반적인 타입이 있다 - Hosted, Dialog, Activity
호스팅이 가장 일반적이고 기본적.
사용하는 UI 프레임워크에 따라 (컴포즈 or 프래그먼트) 탐색 호스트와 그래프를 만드는 방법이 다름.
여기에서는 컴포즈만 다루겠다.
(필요하다면 https://developer.android.com/guide/navigation/design?hl=ko#frameworks 및 https://developer.android.com/guide/navigation/use-graph/navigate?hl=ko#id 참고)
NavHost 컴포저블을 사용하고, Kotlin DSL을 사용하여 NavGraph를 만든다.
NavHost를 추가하는 과정에서 탐색 그래프를 직접 구성할 수 있고, NavController.createGraph() 메서드를 사용하여 NavGraph를 만들어 NavHost에 직접 전달하는 프로그래매틱 방식도 가능하다.
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "profile") {
composable("profile") { Profile( /* ... */ ) }
composable("friendslist") { FriendsList( /* ... */ ) }
// Add more destinations similarly.
}
위 예시를 NavGraph를 별도로 만들어 NavHost에 직접 전달하는 프로그래매틱 방식으로 하면 다음과 같이 된다.
val navGraph by remember(navController) {
navController.createGraph(startDestination = "profile") {
composable("profile") { Profile() }
composable("friendslist") { FriendsList() }
}
}
NavHost(navController, navGraph)
// 예시 코드
// Define the Profile composable.
@Composable
fun Profile(onNavigateToFriendsList: () -> Unit) {
Text("Profile")
Button(onClick = { onNavigateToFriendsList() }) {
Text("Go to Friends List")
}
}
// Define the FriendsList composable.
@Composable
fun FriendsList(onNavigateToProfile: () -> Unit) {
Text("Friends List")
Button(onClick = { onNavigateToProfile() }) {
Text("Go to Profile")
}
}
// Define the MyApp composable, including the `NavController` and `NavHost`.
@Composable
fun MyApp() {
val navController = rememberNavController()
NavHost(navController, startDestination = "profile") {
composable("profile") { Profile(onNavigateToFriendsList = { navController.navigate("friendslist") }) }
composable("friendslist") { FriendsList(onNavigateToProfile = { navController.navigate("profile") }) }
}
}
예시에서 볼 수 있듯이 NavController를 컴포저블에 전달하는 대신 NavHost에 이벤트를 노출한다. 즉, 컴포저블에는 NavHost가 NavController.navigate()를 호출하는 람다를 전달하는 () -> Unit 유형의 매개변수가 있어야 한다.
(참고: 람다에서 추가 데이터를 가져오도록 하려면 (String) -> Unit와 같은 매개변수 유형을 사용하면 된다. 컴포저블에서 여러 매개변수를 사용할 수도 있다.)
(중첩 그래프를 사용할 수도 있다. 여기에는 그래프를 탐색 대상으로 사용하는 작업이 포함된다. 자세한 내용은 https://developer.android.com/guide/navigation/design/nested-graphs?hl=ko 참고)
NavController.navigate())https://developer.android.com/guide/navigation/use-graph/navigate?hl=ko
NavController.navigate() 를 사용하여 탐색할 수 있다.
오버로드가 많은데, 선택해야 하는 오버로드는 정확한 컨텍스트에 해당한다.
컴포저블로 이동하려면 NavController.navigate(route) 를 사용한다. route는 String이며 대상의 키 역할을 함.
route 문자열을 사용하여 이동하려면 먼저 각 대상이 route와 연결되도록 NavGraph를 만들어야 한다. (composable() 해서 만든거)
navigate()를 직접 호출하도록 NavController 참조를 전달하면 안 된다.
단방향 데이터 흐름(UDF) 원칙에 따라 컴포저블은 대신 NavController가 처리하는 이벤트를 노출해야 한다. (navigate 호출을 람다식으로 전달)
// 예시 코드
@Composable
fun MyAppNavHost(
modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController(),
startDestination: String = "profile"
) {
NavHost(
modifier = modifier,
navController = navController,
startDestination = startDestination
) {
composable("profile") {
ProfileScreen(
onNavigateToFriends = { navController.navigate("friendsList") },
/*...*/
)
}
composable("friendslist") { FriendsListScreen(/*...*/) }
}
}
@Composable
fun ProfileScreen(
onNavigateToFriends: () -> Unit,
/*...*/
) {
/*...*/
Button(onClick = onNavigateToFriends) {
Text(text = "See friends list")
}
}
(경고: navigate()는 컴포저블 자체의 일부가 아니라 콜백의 일부로만 호출해야 한다. 이렇게 하면 매 리컴포지션마다 navigate()가 호출되지 않는다.)
참고
https://developer.android.com/develop/ui/compose/navigation?hl=ko
https://developer.android.com/codelabs/basic-android-kotlin-compose-navigation?hl=ko#0