Compose Navigation๐Ÿ”ฅ (2)

ํ‘ธ๋ฅธํ•˜๋Š˜ยท2022๋…„ 7์›” 3์ผ
0

์ปดํฌ์ฆˆ

๋ชฉ๋ก ๋ณด๊ธฐ
5/5
post-custom-banner

Compose Navigation

๐ŸŽ ์ž‘๋™์›๋ฆฌ

HomeScreen -> Profile -> Settings -> ๋’ค๋กœ๊ฐ€๊ธฐ -> HomeScreen -> ๋’ค๋กœ๊ฐ€๊ธฐ -> ์•ฑ์ข…๋ฃŒ

๐ŸŽ ํ”„๋กœ์ ํŠธ

์‹คํ–‰

Build.Gradle ์ถ”๊ฐ€

dependencies {
	def nav_version = "2.4.2"
    // Navigation
    implementation "androidx.navigation:navigation-compose:$nav_version"
}

๐ŸŽ BottomBarScreen

  • Bottom Navigation์— ๋“ค์–ด๊ฐ€๋Š” ์š”์†Œ๋ฅผ ๋„ฃ๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค
  • sealed class์‚ฌ์šฉํ•˜์—ฌ ์ƒํƒœ๊ฐ’์„ ์œ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
  • ์ƒํƒœ๊ฐ’์ด ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ์„œ๋ธŒ ํด๋ž˜์Šค ์ด๊ธฐ์— object ๋ฅผ ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค
sealed class BottomBarScreen(
    val route: String,
    val title: String,
    val icon: ImageVector
){
    object Home: BottomBarScreen(
        route = "Home",
        title = "Home",
        icon = Icons.Default.Home
    )
    object Profile: BottomBarScreen(
        route = "Profile",
        title = "Profile",
        icon = Icons.Default.Person
    )
    object Settings: BottomBarScreen(
        route = "Settings",
        title = "Settings",
        icon = Icons.Default.Settings
    )
}

๐ŸŽ BottomNavGraph

  • NavHostController ์ •ํ•ด ์œ„์น˜์˜ (context)๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค
  • NavHost
    • Compose์—์„œ ํƒ์ƒ‰ ๊ทธ๋ž˜ํ”„์ž…๋‹ˆ๋‹ค
    • ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ ๋Œ€์ƒ์„ ์ง€์ •ํ•˜๋Š” ํƒ์ƒ‰ ๊ทธ๋ž˜ํ”„์™€ NavController๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
  • startDestination ์‹œ์ž‘ ์ง€์ ์„ ์ •ํ•ฉ๋‹ˆ๋‹ค
  • composable ( route = Case ) { ์ด์ผ€์ด์Šค์— ๋ณด์—ฌ์ค˜์•ผํ•˜๋Š” Screen()} ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
@Composable
fun BottomNavGraph(navController: NavHostController) {
    NavHost(
        navController = navController,
        startDestination = BottomBarScreen.Home.route
    ) {
        composable(route = BottomBarScreen.Home.route){
            HomeScreen()
        }
        composable(route = BottomBarScreen.Profile.route){
            ProfileScreen()
        }
        composable(route = BottomBarScreen.Settings.route){
            SettingScreen()
        }
    }
}

๐ŸŽ MainActivity

  • MainScreen ํ˜ธ์ถœ
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Samplenavigation2Theme {
                // A surface container using the 'background' color from the theme
                    MainScreen()
            }
        }
    }
}

๐ŸŽ MainScreen

๐Ÿ BottomBar

  • screens ์œผ๋กœ ์Šคํฌ๋ฆฐ์˜ ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค
  • navBackStackEnty
    • currentBackStackEntryAsState() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜„์žฌ collectAsState๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค
  • ๊ฐ€์ ธ์˜จ ํ•จ์ˆ˜๋ฅผ destination(์ข…์ฐฉ์ง€) ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค
  • BottomNavigation ์•ˆ์— ์Šคํฌ๋ฆฐ์„ ๊ฐ๊ฐ AddItem ํ•ฉ๋‹ˆ๋‹ค
@Composable
fun BottomBar(navController: NavHostController) {
    val screens = listOf(
        BottomBarScreen.Home,
        BottomBarScreen.Profile,
        BottomBarScreen.Settings
    )
    val navBackStackEntry by navController.currentBackStackEntryAsState()
    val currentDestination = navBackStackEntry?.destination

    BottomNavigation {
        screens.forEach { screens ->
            AddItem(screen = screens, currentDestination = currentDestination, navController =navController )
        }
    }
}

๐Ÿ AddItem

  • RowScope๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์–‘ํ•˜๊ฒŒ ์ธ์ž๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.
  • screen / currenDestination / navController ๊ฐ๊ฐ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์Šต๋‹ˆ๋‹ค)
  • BottomNavigationItem ์— BottomBarscreen ์•„์ดํ…œ์„ ๋„ฃ์„๊ฒƒ์ด๋‹ค label / icon... ๋“ฑ๋“ฑ
  • selected => currentDestination?.hierachy?
    • ๊ตฌ์กฐ์˜ ์‹œํ€€์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ณ„์ธต ๊ตฌ์กฐ๋Š” ์ด ๋Œ€์ƒ ์ž์ฒด์—์„œ ์‹œ์ž‘ NavDestination.parentํ•˜์—ฌ ๋ฃจํŠธ ํƒ์ƒ‰ ๊ทธ๋ž˜ํ”„์— ๋„๋‹ฌํ•  ๋•Œ๊นŒ์ง€ ์ด ๋Œ€์ƒ์˜ , ํ•ด๋‹น ๊ทธ๋ž˜ํ”„์˜ ๋ถ€๋ชจ, ๊ณ„์ธต ๊ตฌ์กฐ๊ฐ€ ์ด์–ด์ง‘๋‹ˆ๋‹ค.
  • unselectedContentColor -> ๋ถˆํˆฌ๋ช…๋„๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.
  • onClick ํ–ˆ์„๋•Œ BottomBarScreen.route์—๋”ฐ๋ผ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  • popUpto๋Š” ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ 
    • popUpTo ํ•˜์—ฌ ๋’ค๋กœ๊ฐ€๊ธฐ ๋ˆŒ๋ €์„๋•Œ launchSingTop ํ•˜์—ฌ ์ดˆ๊ธฐ HomeScreen()์œผ๋กœ ๋˜๋Œ์•„์˜ค๊ฒŒํ•จ
@Composable
fun RowScope.AddItem(
    screen: BottomBarScreen,
    currentDestination: NavDestination?,
    navController: NavHostController
) {
    BottomNavigationItem(
        label = {
            Text(text = screen.title)
        },
        icon = {
            Icon(imageVector = screen.icon, contentDescription = "Navigation Icon")
        },
        selected = currentDestination?.hierarchy?.any {
            it.route == screen.route
        } == true,
        unselectedContentColor = LocalContentColor.current.copy(alpha = ContentAlpha.disabled),
        onClick = {
            navController.navigate(screen.route){
                popUpTo(navController.graph.findStartDestination().id)
                launchSingleTop =true
            }
        }
    )
}

๐Ÿ MainScreen

  • rememberNavController()
    • ์•ฑ์˜ ํ™”๋ฉด๊ณผ ๊ฐ ํ™”๋ฉด ์ƒํƒœ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์ปดํฌ์ €๋ธ”์˜ ๋ฐฑ ์Šคํƒ์„ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค
  • Scaffold
    • Scaffold๋Š” ๊ธฐ๋ณธ material design ui๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ์š”์†Œ์ž…๋‹ˆ๋‹ค.
@Composable
fun MainScreen() {
    val navController = rememberNavController()
    Scaffold(
        bottomBar = { BottomBar(navController = navController)}
    ) {
        BottomNavGraph(navController = navController)

    }
}

GitHub : ์ฝ”๋“œ ์ž๋ฃŒ

post-custom-banner

0๊ฐœ์˜ ๋Œ“๊ธ€