[Compose] Navigation

KSang·2024년 1월 31일
0

compose

목록 보기
1/5

Compose Navigation

    val nav_version = "2.7.6"

    implementation("androidx.navigation:navigation-compose:$nav_version")

일단 라이브러리를 추가해준다.


        setContent {
            val navController = rememberNavController()
        }
...

@Composable
fun FirstScreen(){
    
}
@Composable
fun SecondScreen(){
    
}
@Composable
fun ThirdScreen(){
    
}

전환할 화면들을 만들어 주고 네비를 관리할 navController를 만들어준다

문제가 생겼는데

        setContent {
            val navController = rememberNavController()
            NavHost(navController = navController, startDestination = "first"){
                composable("first"){
                    FirstScreen()
                }
            }

하면 기존에 가능했지만

2.7.6 버전에 들어오면서 NavHost안에 startDestination이 없어졌다.

버전이 바뀌면서 방식이 변경된거 같다

그럼 뭐 뜯어봐야지

image

위에 주석으로 설명한 부분을 보면 graph가 destination을 관리하는 부분일것 같다.

NavGraph를 들어가보면
image

NavGraph는 ID별로 가져올 수 있는 [NavDestination] 노드의 모음이라고 되어있다.

그럼 NavDestination을 들어가보면

image

전체 탐색 그래프 내의 하나의 노드를 나타냈고

Navigator.createDestination를 통해 생성된다고 되어있다.

네비게이터는 이미 만들었다

            val navController = rememberNavController()
...
public fun rememberNavController(
    vararg navigators: Navigator<out NavDestination>
): NavHostController {

rememberNavController를 보면 Navigator인걸 확인 할 수 있는데

그럼 이걸로 NavDestination을 만들어보자

navController.을 쳐보면 누가봐도 써야할것 같은 createGraph가 보인다

image

        setContent {
            val navController = rememberNavController()
            val navGraph = navController.createGraph(startDestination = "first"){
                composable("first") {
                    FirstScreen ()
                }
                composable("second") {
                    SecondScreen ()
                }
                composable("third") {
                    ThirdScreen()
                }
            }

            NavHost(navController = navController, graph = navGraph)
        }

NavHost에 있던 builder부분도 Destination관리를 Graph에서 하니 자연스럽게 Graph로 옮겨가서

Graph에 람다로 composable을 설정해주고

NavHost에 컨트롤러와 함께 넣어준다.

이제 화면에 표시할 스크린을 만들어주자

@Composable
fun FirstScreen(
    onClick: (Int , String?) -> Unit
) {
    val (value , setValue) = remember {
        mutableStateOf("")
    }

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(text = "첫화면")
        Spacer(modifier = Modifier.height(16.dp))
        Button(onClick = { onClick(2, null) }) {
            Text(text = "두번째")
        }
        Spacer(modifier = Modifier.height(16.dp))
        TextField(value = value, onValueChange = setValue)
        Button(onClick = { onClick(3, value) }) {
            Text(text = "세번째")
        }
    }
}

@Composable
fun SecondScreen(
    onClick: (Int) -> Unit
) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(text = "두번째 화면")
        Spacer(modifier = Modifier.height(16.dp))
        Button(onClick = { onClick(1) }) {
            Text(text = "뒤로")
        }
    }
}

@Composable
fun ThirdScreen(value: String,
                onClick: (Int) -> Unit) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(text = "세번째 화면")
        Spacer(modifier = Modifier.height(16.dp))
        Text(text = "$value")
        Button(onClick = { onClick(1) }) {
            Text(text = "뒤로")
        }
    }
}

버튼으로 이동하게 구성했고 첫번째 화면에서 세번째 화면으로 이동할때 텍스트 필드의 값을 넘겨 줄 거다

 setContent {
            val navController = rememberNavController()
            val navGraph = navController.createGraph(startDestination = "first"){
                composable("first") {
                    FirstScreen { int, value ->
                        when (int) {
                            2 -> navController.navigate("second")
                            3 -> navController.navigate("third/$value")
                            else -> Log.e("main", "unknown: $int, $value")
                        }
                    }
                }
                composable("second") {
                    SecondScreen { navController.navigate("first") }
                }
                composable("third/{value}") {backStackEntry ->
                    ThirdScreen( value = backStackEntry.arguments?.getString("value") ?: "") { navController.navigate("first") }
                }
            }

            NavHost(navController = navController, graph = navGraph)
        }

콜백으로 받아 몇번째로 이동하는지 구별하고

third/$value로 Url처럼 작성 할 수있다.

받는 부분에선

composable("third/{value}") 넘겨 받을 부분을 중괄호로 감싸준다.

그리고 composable을 열어보면

public fun NavGraphBuilder.composable(
    route: String,
    arguments: List<NamedNavArgument> = emptyList(),
    ...
    content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit
) {
    ...

public class NavBackStackEntry private constructor(
    private val context: Context?,

콜백에서 NavBackStackEntry객체가 있는데 Context를 받는다 이걸 이용해서

backStackEntry.arguments?.getString("value") ?: ""

이렇게 번들을 얻을 수 있다.

ezgif-7-8b6ff2fccf

0개의 댓글