Bookmark profile

안드로이드 네비게이션 바 설계, 네비게이션은 크게 두가지로 나눌 수 있습니다.

하단 탭을 가지고있는 화면과 가지고있지 않은 화면!

이 두개의 화면을 분리해서 네비게이션을 구성해보려고 합니다.

저는 첫번째 그룹을 온보딩(onboarding) 이라고 정의하고,

두번째 그룹은 메인(main) 이라고 정의해보겠습니다.

우선 두개의 그룹에 화면을 임의대로 설정해서 오타를 방지하기 위해 객체로 만들어 줍니다.

안드로이드 네비게이션 바, 화면 라우팅 객체 만들기

// Screen.kt

sealed class Screen(val route: String) {
    // Onboarding Screens
    data object Onboarding1 : Screen("onboarding_1")
    data object Onboarding2 : Screen("onboarding_2")

    // Main Screens
    data object Screen1 : Screen("screen_1")
    data object Screen2 : Screen("screen_2")
    data object Screen3 : Screen("screen_3")
    data object Screen4 : Screen("screen_4")
}

이제 그룹을 나누어서 화면들을 묶어줍니다.

안드로이드 네비게이션 바, 네비게이션 그래프 만들기

AppNavigationGraph.kt

// AppNavigationGraph.kt

fun NavGraphBuilder.onboardingGraph(navController: NavHostController) {
    navigation(route = "onboarding", startDestination = Screen.Onboarding1.route) {
        composable(Screen.Onboarding1.route) { Onboarding1(navController) }
        composable(Screen.Onboarding2.route) { Onboarding2(navController) }
    }
}

fun NavGraphBuilder.mainGraph(navController: NavHostController) {
    navigation(route = "mainGraph", startDestination = Screen.Screen1.route) {
        composable(Screen.Screen1.route) { Screen1(navController) }
        composable(Screen.Screen2.route) { Screen2(navController) }
        composable(Screen.Screen3.route) { Screen3(navController) }
        composable(Screen.Screen4.route) { Screen4(navController) }
    }
}

이어서, 메인 그룹(mainGraph)에 하단 탭을 추가하기 위해 컴포즈(UI)를 하나 만들어 줍니다.

MainWithBottomNavigation.kt

// MainWithBottomNavigation.kt

@Composable
fun MainWithBottomNavigation() {
    val mainNavController = rememberNavController()

    Scaffold(
        bottomBar = {
            BottomNavigationBar(mainNavController)
        }
    ) {it ->
        NavHost(
            navController = mainNavController,
            startDestination = "mainGraph"
        ) {
            mainGraph(mainNavController)
        }
    }
}

여기에서 사용할 하단 탭은 간단하게 만들어 보겠습니다. items는 위에서 정의한 메인의 4개 화면이 들어갑니다.

원하는 순서에 맞게 변경해서 사용해도 무관합니다.

@Composable
fun BottomNavigationBar(navController: NavHostController) {
    val items = listOf(
        Screen.Screen1,
        Screen.Screen2,
        Screen.Screen3,
        Screen.Screen4,
    )

    Row {
        val navBackStackEntry by navController.currentBackStackEntryAsState()
        val currentRoute = navBackStackEntry?.destination?.route

        items.forEach { screen ->
            Column (modifier = Modifier.clickable(onClick = {
                navController.navigate(screen.route) {
                    popUpTo(navController.graph.startDestinationId) {
                        saveState = true
                    }
                    launchSingleTop = true
                    restoreState = true
                }
            })) {
                Text(screen.route)
                if (currentRoute == screen.route) {
                    Text("Selected")
                } else {
                    Text("-")
                }
            }
        }
    }
}

이제 이 하단 탭을 추가한 MainWithBottomNavigation 컴포즈와 NavGraphBuilder.onboardingGraph를 가지고 네비게이션을 구성해줍니다.

만들어진 네비게이션 그래프를 연결하기

@Composable
fun AppNavigation(navController: NavHostController) {
    NavHost(navController, startDestination = "main") {
        // Onboarding Screens
        onboardingGraph(navController)

        // Main Screens with Bottom Navigation
        composable("main") { MainWithBottomNavigation() }
    }
}

지금까지의 구조를 요약해보면 다음과 같습니다.

AppNavigation
- onboarding
- main 
-- mainGraph + BottomNavigationBar

네비게이션은 앱을 만들 때마다 재사용이 가능할 것 같습니다.

이제 네비게이션을 완성했으니, 직접 화면에 띄워봐야합니다.

메인 액티비티로 가서 네비게이션을 추가해줍니다!

MainActivity.kt

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyAppTheme {
                // [시작] 추가한 부분
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    val navController = rememberNavController()
                    AppNavigation(navController = navController)
                }
                // [끝] 추가한 부분
            }
        }
    }
}

// [시작] 미리보기
@Preview(showBackground = true)
@Composable
fun App() {
    MyAppTheme {
        val navController = rememberNavController()
        AppNavigation(navController = navController)
    }
}
// [끝] 미리보기