컴포즈 내비게이션 튜토리얼

손현수·2024년 4월 7일

안드로이드 Compose

목록 보기
21/25

이 프로젝트는 3개의 목적지 화면(홈, 웰컴, 프로필)으로 구성된다. 홈 화면은 하나의 텍스트 필드를 갖고 있으며 사용자가 이름을 입력한다. 버튼을 클릭하면 웰컴 화면으로 이동하면서 사용자의 이름을 인수로 전달하며, 이 이름은 웰컴 메시지에 표시된다. 웰컴 화면도 하나의 버튼을 포함하며, 이 버튼을 클릭하면서 프로필 화면으로 이동할 수 있다. 이 버튼은 오로지 popUpTo() 내비게이션 옵션 메서드를 실험하기 위한 것이다.

내비게이션 경로 선언하기

sealed class NavRoutes(val route: String) {
    data object Home: NavRoutes("home")
    data object Welcome: NavRoutes("welcome")
    data object Profile: NavRoutes("profile")
}

홈 화면 추가하기

@Composable
fun Home(navController: NavHostController) {
    var userName by remember {
        mutableStateOf("")
    }
    val onUserNameChange = { text: String -> 
        userName = text
    }
    
    Box(
        modifier = Modifier
            .fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        Column(
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            CustomTextField(
                title = "Enter your name", 
                textState = userName, 
                onTextChange = onUserNameChange
            )
            
            Spacer(modifier = Modifier.size(30.dp))
            
            Button(
                onClick = { }
            ) {
                Text(text = "Register")
            }
        }
    }
}

@Composable
fun CustomTextField(
    title: String,
    textState: String,
    onTextChange: (String) -> Unit
) {
    OutlinedTextField(
        value = textState, 
        onValueChange = { onTextChange(it) },
        singleLine = true,
        label = { Text(title) },
        modifier = Modifier.padding(10.dp),
        textStyle = TextStyle(
            fontWeight = FontWeight.Bold,
            fontSize = 30.sp
        )
    )    
}

웰컴 화면 추가하기

@Composable
fun Welcome(navController: NavHostController) {
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        Column(
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(text = "Welcome", style = MaterialTheme.typography.headlineSmall)
            
            Spacer(modifier = Modifier.size(30.dp))
            
            Button(onClick = {}) {
                Text(text = "Set up your Profile")
            }
        }
    }
}

프로필 화면 추가하기

@Composable
fun Profile() {
    Box(
        modifier = Modifier
            .fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        Text("Profile Screen", style = MaterialTheme.typography.headlineSmall)
    }
}

내비게이션 컨트롤러와 호스트 만들기

기본 요소가 준비되었으므로 내비게이션 컨트롤러와 내비게이션 호스트 인스턴스를 만든다. MainActivity 파일의 MainScreen 컴포저블을 다음과 같이 수정한다.

@Composable
fun MainScreen() {
    val navController = rememberNavController()

    NavHost(
        navController = navController,
        startDestination = NavRoutes.Home.route
    ) {
        composable(NavRoutes.Home.route) {
            Home(navController = navController)
        }

        composable(NavRoutes.Welcome.route) {
            Welcome(navController = navController)
        }

        composable(NavRoutes.Profile.route) {
            Profile()
        }
    }
}

MainScreen 함수는 rememberNavController() 메서드 호출을 통해 내비게이션 컨트롤러 인스턴스를 얻는 것에서 시작한다. NavHost 컴포넌트가 호출되고, 홈 화면을 시작 목적지로 할당한다. composable() 메서드가 호출되고 각 화면에 대한 경로가 추가된다.

화면 내비게이션 구현하기

내비게이션은 홈 화면과 웰컴 화면의 Button 컴포넌트가 클릭될 때 초기화되어야 한다. 두 컴포저블을 이미 navigate() 메서드를 호출할 내비게이션 컨트롤러에 전달되었다. Button 컴포넌트의 onClick 프로퍼티에 내비게이션 코드를 추가한다.

            Button(
                onClick = {
                    navController.navigate(NavRoutes.Welcome.route)
                }
            ) {
                Text(text = "Register")
            }

위는 Home.kt의 버튼 코드이다.

            Button(onClick = {
                navController.navigate(NavRoutes.Profile.route)
            }) {
                Text(text = "Set up your Profile")
            }

위는 Welcome.kt의 버튼 코드이다.

사용자 이름 인수 전달하기

NavHost 선언 안의 웰컴 목적지 경로를 확장해서 텍스트 필드에 입력된 사용자 이름이 내비게이션 과정에서 웰컴 화면으로 전달되게 한다. 먼저, Welcome() 함수가 사용자 이름을 받아 화면에 표시하도록 수정한다.

@Composable
fun Welcome(navController: NavHostController, userName: String?) {
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        Column(
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(text = "Welcome, $userName", style = MaterialTheme.typography.headlineSmall)

다음으로는 NavHost에서 Welcome 컴포저블에 유저 이름을 전달할 수 있도록 수정한다.

        composable(NavRoutes.Welcome.route + "/{userName}") { backStackEntry ->
            val userName = backStackEntry.arguments?.getString("userName")
            Welcome(navController = navController, userName)
        }

마지막으로 Home에서 Welcome으로 넘어가는 버튼을 클릭할 때 유저의 이름을 넘겨주도록 수정한다.

            Button(
                onClick = {
                    navController.navigate(NavRoutes.Welcome.route + "/$userName")
                }
            ) {
                Text(text = "Register")
            }

앱을 실행시키면 홈 -> 웰컴 -> 프로필 화면으로 이동하는 것을 확인할 수 있다. 프로필 화면에서 홈 화면으로 돌아가기 위해서는 뒤로가기를 두 번 눌러야 하는데 popUpTo() 함수를 통해 프로필 화면에서 뒤로가기 한 번으로 홈 화면으로 이동할 수 있도록 변경할 수 있다.

            Button(onClick = {
                navController.navigate(NavRoutes.Profile.route) {
                    popUpTo(NavRoutes.Home.route)
                }
            }) {
                Text(text = "Set up your Profile")
            }

Welcome 페이지의 버튼에서 navigate() 함수의 후행 람다에 popUpTo() 코드를 위처럼 추가하면 프로필 화면에서 뒤로가기 한 번으로 홈 화면으로 돌아갈 수 있다.

profile
안녕하세요.

0개의 댓글