CareVision에서 Jetpack Compose Navigation 설계와 구현 방법

강유리 (Rein)·2024년 11월 10일
0

CareVision
환자 곁에서 늘 함께, 간호사의 눈이 되어주는 환자 모니터링 서비스
Github : https://github.com/SSU-Capstone-Aurora
3-2 소프트웨어학부 캡스톤1 수업에서 진행하는 프로젝트 입니다.

CareVision 프로젝트에서는 다음과 같이 Navigation을 구현했습니다.

File Changes

1. MainActivity

Navigation을 위해 총 가지의 파일에 수정 또는 추가가 필요합니다.

우선 프로젝트의 최상위 액티비티인 MainActivity에서 NavController를 생성합니다.

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            CVTheme {
                // navController를 생성하고, 이를 NavHost에 전달
                val navController = rememberNavController()

                // NavHost는 여러개의 composable을 가지고 있는데, 이 composable들을 관리하는 역할
                CVNavHost(
                    navController = navController,
                    startDestination = Intro,
                )
            }
        }
    }

코드설명 - NavController

  • rememberNavController()로 생성한 NavControllerMainActivityComposable 트리 내에서만 동일한 인스턴스를 유지할 수 있도록 합니다.
  • Activity가 재생성되거나 앱의 Compose 트리가 새로 생성되면, 새로운 NavController 인스턴스가 다시 생성될 것입니다.
  • NavController는 보통 각각의 NavHost마다 인스턴스가 생성되어 해당 NavHost의 네비게이션 상태를 관리하도록 합니다.

2. 화면이동할 각 Screen 파일들

CareVision에서는 사진과 같이 두개의 흐름으로 기능이 나뉘게 됩니다.
관리자, 간호사 두 분야의 사용자가 있기 때문에 각각의 사용자에 맞는 네비게이션 그래프가 그려져야 합니다.

최초 로그인 화면 Intro에서 관리자, 간호사를 선택할 수 있으며
각각의 로그인 화면에서는 회원가입 화면으로 이동할수도 있습니다.
이러한 네비게이션 구조를 위해 중첩 구조를 활용했습니다.

간호사 로그인, 회원가입을 예시로 보겠습니다.
우선 간호사 피쳐의 패키지 구조는 feat > nurse > auth > login, signup으로 되어 있습니다.

로그인 Screen

위와 같이 필요한 Screen의 Composable함수를 구현합니다.

3. 각 Screen별 네비게이션 관련 파일 생성

그리고 각 패키지 안에 각 스크린에 대한 navigation파일을 만듭니다.

Intro (최초 로그인 화면)에서 간호사 로그인 또는 관리자 로그인으로 화면 이동을한다고 가정했을 때의 코드들입니다.
따라서 Intro, AdminLogin, NurseLogin이라는 도착지가 있어야 합니다.

package com.aurora.carevision.feature.intro

import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import kotlinx.serialization.Serializable

// Intro 화면을 나타내는 Intro 클래스를 선언, Route로 사용
@Serializable
data object Intro

// 외부에서 Intro로 이동할 수 있도록 NavHostController에 navigateToIntro 함수를 추가
fun NavHostController.navigateToIntro(navOptions: NavOptions) = navigate(Intro, navOptions)

// Intro 화면을 그리는 composable 함수를 NavGraphBuilder에 추가
fun NavGraphBuilder.initialLoginScreen(
    navigateToLogin: () -> Unit,
    navigateToSignUp: () -> Unit,
    navigateToAdminLogin: () -> Unit,
) {
    composable<Intro> {
        InitialLoginScreen(
            onLoginClick = navigateToLogin,
            onSignUpClick = navigateToSignUp,
            onAdminLoginClick = navigateToAdminLogin,
        )
    }
}
package com.aurora.carevision.feature.nurse.auth.login

@Serializable
data object NurseLogin

fun NavHostController.navigateToNurseLogin(navOptions: NavOptions? = null) = navigate(NurseLogin, navOptions)

fun NavGraphBuilder.nurseLoginScreen(
    navigateToHome: () -> Unit,
    navigateToSignUp: () -> Unit,
    navigateToBack: () -> Unit,
) {
    composable<NurseLogin> {
    // composable 스크린으로 네비게이션 람다 함수 전달
        NurseLoginScreen(
            navigateToHome = navigateToHome,
            navigateToSignUp = navigateToSignUp,
            navigateToBack = navigateToBack,
        )
    }
}
package com.aurora.carevision.feature.admin.auth.login

@Serializable
data object AdminLogin

fun NavHostController.navigateToAdminLogin(navOptions: NavOptions? = null) = navigate(AdminLogin, navOptions)

fun NavGraphBuilder.adminLoginScreen(
    navigateToHome: () -> Unit,
    navigateToSignUp: () -> Unit,
) {
    composable<AdminLogin> {
        AdminLoginScreen(
            
        )
    }
}

이제 각 Screen파일에 대해 만든 Navigation의 확장 함수들을 사용하여 NavHost에서 네비게이션을 할 수 있습니다.

4. NavHost.kt

아래 CareVision(CV)의 NavHost파일 내에 있는 CVNavHost 함수는 CareVision 앱 내 주요 화면들의 탐색 경로를 정의합니다.
또한 각 화면에서 다음 화면으로 전환하거나 뒤로 가기 기능을 포함한 네비게이션 흐름을 관리합니다.

import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.rememberNavController

@Composable
fun CVNavHost(
    navController: NavHostController = rememberNavController(),
    startDestination: Any = Intro,
) {
    NavHost(
        navController = navController,
        startDestination = startDestination
    ) {
        initialLoginScreen(
            navigateToLogin = { navController.navigateToNurseLogin() },
            navigateToSignUp = { navController.navigateToNurseSignUp() },
            navigateToAdminLogin = { navController.navigateToAdminLogin() }
        )
    }
}

최초 화면인 initialLoginScreen 에서는 간호사 로그인, 간호사 회원가입, 관리자 로그인 총 3가지의 스크린으로 이동할 수 있기에 이와 같이 NavGraphBuilder의 확장함수인 initialLoginScreen의 매개변수로 navcontroller 확장함수들(navigate 함수)을 람다함수로 전달합니다.

각 화면으로 화면전환이 된 후에 이후 화면으로 또 navigation이 이루어져야 할 것입니다.

그렇기에 NavHost에 계속해서 이동한 화면에 대한 NavGraphBuilder 확장함수를 추가하거나 추가 후에 네비게이션 함수를 넘겨줌으로써 화면 이동 흐름을 만들어갈 수 있습니다.

5. 최종 코드

화면 이동이 필요할 때마다 NavHost 내에 코드 추가가 계속 필요할 텐데요.
이전에 이야기한 아래 사진 흐름은 이와 같이 NavHost 파일이 구성될 것입니다.


@Composable
fun CVNavHost(
    navController: NavHostController = rememberNavController(),
    startDestination: Any = Intro,
) {
    NavHost(
        navController = navController,
        startDestination = startDestination
    ) {
        initialLoginScreen(
            navigateToLogin = { navController.navigateToNurseLogin() },
            navigateToSignUp = { navController.navigateToNurseSignUp() },
            navigateToAdminLogin = { navController.navigateToAdminLogin() }
        )

        nurseLoginScreen(
            navigateToSignUp = { navController.navigateToNurseSignUp() },
            navigateToBack = { navController.popBackStack() }
        )

        nurseSignUpScreen(
            navigateToBack = { navController.popBackStack() }
        )

        adminLoginScreen(
            navigateToSignUp = { navController.navigateToAdminSignUp() }
        )

        adminSignUpScreen(
            navigateToBack = { navController.popBackStack() }
        )
    }
}

해당 코드가 모인 PR

지금은 단순 navigation 관련 코드만 다루었는데요,
더 많은 기능을 담은 서비스 구현을 위해서는
bottomNavigation, NavOptions 등 또다른 navigation 코드들이 필요하게 됩니다. 이에 대한 내용은 다음 포스팅에서 다루겠습니다.

profile
(멋쨍이) Android Developer (하고싶다)

0개의 댓글

관련 채용 정보