본문 바로가기

android

Android Compose Navigation 기초

Android에서 화면 이동은 주로 Navigation을 통해 이동을 했다.

 

처음 개발했을 떄는 직접 Fragment Manager와 Fragment Transaction을 이용해 개발을 했었다.

 

요즘 Compose로 개인 프로젝트를 개발을 하고 있는데 앱의 화면이 하나인 경우는 극히 적으니 Compose의 Navigation을 배워야 했다.

 

 필자가 이해한 내용을 위주로 적는 것이니 틀린 부분이 있을 수 도 있음 !!

 

해당 이미지는 Android Developer에 있는 그림입니다.

맨 처음 xml로 개발을 하게 되면 Navigation을 쓰게 되었을 때 보는 화면이다. 

 

자주 써서 그런지 사용하기가 매우 편했다. 화면 추가하고 드래그로 연결만 하면 되니까.

 

Compose에서는 xml같은 화면이 없어서 그런가 저런식으로 안 쓰는 것 같다.

 

본인도 유튜브랑 다른 블로그를 보면서 지금 하고 있는 프로젝트에 넣는 것이라 ... 많이 내용이 부족하고 이해가 안되는 부분이 있을 수 있다.

 

우선은 build.gradle에 해당 의존성을 추가해줍시다.

implementation ("androidx.navigation:navigation-compose:2.7.2")

 

@Composable
fun ScreenOne(navigateToScreenTwo: () -> Unit) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "Screen 1")
        Button(onClick = navigateToScreenTwo) {
            Text(text = "Navigate to next screen")
        }
    }
}

@Composable
fun ScreenTwo(
    navigateToScreenThree: () -> Unit, navigateBack: () -> Unit
) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "Screen 2")
        Button(onClick = navigateToScreenThree) {
            Text(text = "Navigate to next screen")
        }
        Button(onClick = navigateBack) {
            Text(text = "Navigate to back")
        }
    }
}

@Composable
fun ScreenThree(
    navigateBack: () -> Unit, navigateBackToScreenOne: () -> Unit
) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "Screen 3")
        Button(onClick = navigateBack) {
            Text(text = "Navigate to back")
        }
        Button(onClick = navigateBackToScreenOne) {
            Text(text = "Navigate back to screen 1")
        }
    }
}

 

그리고 간단하게 화면 3개를 만들어 주었습니다.

 

그리고 해당 object를 만드는데요. 제가 이해한것은 이제 이게 기존의 xml Navigation에서 nav_graph 같은 역할을 하지 않나 싶습니다. 

object Route {
    const val screenOne = "screenOne"
    const val screenTwo = "screenTwo"
    const val screenThree = "screenThree"
}

 

 

navController를 추가해주시고

val navController = rememberNavController()

 

다음 NavHost를 만들어 줍시다

NavHost(navController = navController, startDestination = Route.screenOne) {
//이 부분에 compose 화면이 들어가게 됨
 }

 

startDestination은 이름에서도 알 수 있다싶이 시작화면을 정할 수 있습니다. 지금은 Route.screenOne으로 되어 있는데요. 해당 화면을 밑에서 정해주시면 됩니다.

 

 

이렇게 NavHost 안에 composable을 채워 주시면 해당 화면으로 이동할 수 있게 됩니다.

 

첫번째 composable의 route는 Route.sceenOne << 이제 이 composable이 첫화면이 됩니다. 

composable(route = Route.screenOne) {
    ScreenOne(navigateToScreenTwo = {
        navController.navigate(Route.screenTwo)
    })
}

composable(route = Route.screenTwo) {
    ScreenTwo(navigateToScreenThree = { navController.navigate(Route.screenThree) },
        navigateBack = {
            navController.popBackStack()
        })
}

composable(route = Route.screenThree) {
    ScreenThree(navigateBack = {
        navController.popBackStack()
    }, navigateBackToScreenOne = {
        navController.popBackStack(
            route = Route.screenOne,
            inclusive = false
        )
    })

}

 

첫번째 화면의 코드입니다.

@Composable
fun ScreenOne(navigateToScreenTwo: () -> Unit) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "Screen 1")
        Button(onClick = navigateToScreenTwo) {
            Text(text = "Navigate to next screen")
        }
    }
}

 

navigationToScreenTwo를 아래와 같이 넘겨주기 때문에 

navController.navigate(Route.screenTwo)

버튼을 누르면 이제 두 번째 화면으로 넘어가게 됩니다.

 

 

NavHost의 마지막 화면에 대한 정의 인데요.

composable(route = Route.screenThree) {
    ScreenThree(navigateBack = {
        navController.popBackStack()
    }, navigateBackToScreenOne = {
        navController.popBackStack(
            route = Route.screenOne,
            inclusive = false
        )
    })
}

 

마지막 화면인데요. 여기서 navigateBackToScreenOne에서 inclusive가 보통은 true인데 여기서 false인 이유는 뒤로가기 버튼을 누르면 흰색 화면이 나옵니다. false로 두면 이전화면이 유지되지만 true인 경우에는 화면이 날라가서 흰색 화면만 나오게 됩니다.

 

 

 

다음에는 Navigation을 이용해 인자를 보내는 법을 알아보겠습니다.