Nutri Capture ํ๋ก ํธ์๋ ๊ฒ์๊ธ ์๋ฆฌ์ฆ
- Scaffold
- NavHost
- NavigationBar
- NutrientScreen ๊ตฌ์กฐ ์ก๊ธฐ
- NutrientScreen์ ๋ฌดํ ์คํฌ๋กค
- ๋ฌดํ ์คํฌ๋กค ๋ก์ง ๋ถ๋ฆฌ
- ์ญ๋ฐฉํฅ ๋ฌดํ ์คํฌ๋กค
- requestScrollToItem()์ ์ด์ฉํ ๊น๋ํ ์ญ๋ฐฉํฅ ๋ฌดํ ์คํฌ๋กค
- ์คํฌ๋กค ๋ก์ง View์ ์ผ์
- Card
- ์ฑํ UI ๊ตฌ์กฐ ์ก๊ธฐ
- ๋ฌดํ ์คํฌ๋กค ๋ก์ง ๋ฆฌํฉํ ๋ง
- INSERT ๋ฐ DELETE ๋ฒํผ ๊ตฌํ
- item ์ถ๊ฐใ์ ๊ฑฐ ์ ๋๋ฉ์ด์
- bottomBar ๋์ ๋ณ๊ฒฝ
- Typography
- Dimens์ ํจ๊ป ChatBar ๋ง๋ค๊ธฐ
- ์์ด์ฝ ์ ์ (1์ฐจ)
- ์ฝ๋ ์ ๋ฆฌ
- windowInsetsPadding()
- ์ปค์คํ BottomSheetScaffold ๊ฐ๋ฐ ์ ์
- 'ํผ์' ์์ด์ฝ ๊ตฌํ
- 'ํผ์' ์์ด์ฝ ์์ ์ ์ฉ
- NutrientBottomSheet ๋ถ๋ถ ๊ตฌํ
#1 ๊ฐ์
#1-1 NavigationBar์ ๋ฃ์ ์์ด์ฝ ๊ฐ์ ธ์ค๊ธฐ
Material Symbols and Icons - Google Fonts
Material Symbols are our newest icons consolidating over 2,500 glyphs in a single font file with a wide range of design variants.
fonts.google.com
NavigationBar์ ๊ตฌํํ๊ธฐ ์ํด์ ๋จผ์ ์์ด์ฝ์ด ํ์ํ๋ค. ์ ํ์ด์ง์์ SVG ์์ด์ฝ์ ๋ค์ด๋ก๋ํ๋ค. ์ด์ ๊ฒ์๊ธ์์ ๋ง๋ NavHost์ Destination์ 3๊ฐ์ด๋ฏ๋ก ๊ฐ๊ฐ์ Destination์ ์ด์ธ๋ฆฌ๋ ์์ด์ฝ 3๊ฐ๋ฅผ ๊ณจ๋ผ ๋ค์ด๋ก๋ ํ๋ค (์ฐธ์กฐ: ์ฒซ๋ฒ์งธ ์์ด์ฝ, ๋๋ฒ์งธ ์์ด์ฝ, ์ธ๋ฒ์งธ ์์ด์ฝ).
#1-2 NavigationBar ๊ตฌํ
[Android] Jetpack Compose - Scaffold
#1 ๊ฐ์#1-1 Scaffold์ ์ฌ์ ์ ์๋ฏธScaffold๋ ๋น๊ณ((๊ฑด์ค) ๋์ ๊ณณ์์ ๊ณต์ฌ๋ฅผ ํ ์ ์๋๋ก ์์๋ก ์ค์นํ ๊ฐ์ค๋ฌผ)๋ผ๋ ๋จ์ด๋ก ๋ฒ์ญ๋๋ค. #1-2 Scaffold in Jetpack Compose Jetpack Compose | Android Developers์ด
kenel.tistory.com
์ ๊ฒ์๊ธ์ #4-3์์ ์ธ๊ธํ๋ NavigationBar ๋ฐ NavigationItem์ ๊ตฌํํ๋ค.
#2 ์ฝ๋
#2-1 SVG ์ด๋ฏธ์ง๋ฅผ Vector ์ด๋ฏธ์ง๋ก ๋ณ๊ฒฝ

[res] โ [drawable] โ [๋ง์ฐ์ค ์ค๋ฅธ์ชฝ ๋ฒํผ ํด๋ฆญ] โ [New] โ [Vector Asset]์์ #1-1์์ ๋ค์ด๋ก๋ํ๋ 3๊ฐ์ SVG ํ์ผ์ Vector ํํ๋ก ๋ณํํ์ฌ ํ๋ก์ ํธ์ ์ถ๊ฐํ๋ค.
#2-2 Destination ์ ๋ณด๋ฅผ ๋ด๋ sealed class ์ ์ธ
...
class MainActivity : ComponentActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
...
setContent {
NutricapturenewTheme {
...
Scaffold(
...
) { innerPadding ->
// (2) NavHost ์์
NavHost(
navController = navController,
startDestination = Destination.NutrientInputScreen.route,
modifier = Modifier.padding(innerPadding)
) {
composable(route = Destination.NutrientInputScreen.route) {
NutrientInputScreen(
scope = scope,
snackbarHostState = snackbarHostState
)
}
composable(route = Destination.StatisticsScreen.route) {
StatisticsScreen(
scope = scope,
snackbarHostState = snackbarHostState
)
}
composable(route = Destination.UserInfoScreen.route) {
UserInfoScreen(
scope = scope,
snackbarHostState = snackbarHostState
)
}
}
}
}
}
}
}
// (1) sealed class ์ ์ธ
sealed class Destination(val route: String, val title: String, val iconId: Int) {
data object NutrientInputScreen : Destination("nutrientInputScreen", "์บก์ฒ", R.drawable.pan_tool_alt)
data object StatisticsScreen : Destination("statisticsScreen", "ํต๊ณ", R.drawable.stacked_line_chart)
data object UserInfoScreen : Destination("userInfoScreen", "๋ด ์ ๋ณด", R.drawable.manage_accounts)
}
@Composable
fun SampleContent( ... ) { ... }
(1) sealed class ์ ์ธ
3๊ฐ์ Destination์ ์ฌ์ฉํ ๊ฒ์ด๋ฏ๋ก 3๊ฐ์ ์์ ํด๋์ค๋ฅผ ๋๋ค.
(2) NavHost ์ ์ธ
ํ๋ ์ฝ๋ฉํด๋์๋ startDestination ํ๋กํผํฐ์ ๊ฐ ๊ทธ๋ฆฌ๊ณ ๊ฐ Destination์ route ์์ฑ์ ๊ฐ์ (1)์์ ๋ง๋ sealed class๋ค์ ๊ฐ์ผ๋ก ์์ ํ๋ค.
#2-3 NavigationBar ์ ์ธ (ํ ์ก๊ธฐ)
...
class MainActivity : ComponentActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
...
setContent {
NutricapturenewTheme {
...
Scaffold(
...
bottomBar = {
MainNavigationBar(navController)
},
...
) { innerPadding ->
...
}
}
}
}
@Composable
private fun MainNavigationBar(navController: NavHostController) {
/* TODO */
}
}
sealed class Destination(val route: String, val title: String, val iconId: Int) {
...
}
@Composable
fun SampleContent( ... ) { ... }
์์ ์ฑ์๋ฃ๊ธฐ์ฉ์ผ๋ก Scaffold์ bottomBar์ ๋ฃ์ด์ฃผ์๋ BottomAppBar()๋ฅผ ์ญ์ ํ๊ณ ๊ทธ ๋์ ์ฌ์ฉ์ ์ ์ ์ปดํฌ์ ๋ธ ํจ์ MainNavigationBar()๋ฅผ ๋ฃ์ด์ฃผ์๋ค. ์ด ํจ์์์ NavigationBar๋ฅผ ๊ตฌํํ ๊ฒ์ด๋ค (TODO ์ฃผ์ ๋ถ๋ถ). ๋ฐ๋ผ์ Navigation ๋์์ ์ฃผ์ฒด์ธ NavHostController๋ก ์ธ์๋ก ๋ฐ๊ฒ ๋ง๋ ๋ค.
์๋ ์ฝ๋๋ TODO ์ฃผ์ ๋ถ๋ถ์ ๊ตฌํํ ๊ฒ์ด๋ค.
#2-4 NavigationBar ๋ฐ NavigationBarItem ๊ตฌํ
// (1) NavigationBar์ ๋ค์ด๊ฐ ์์ดํ
๋ฆฌ์คํธ
val items = listOf(
Destination.NutrientInputScreen,
Destination.StatisticsScreen,
Destination.UserInfoScreen
)
NavigationBar {
// (2) ํ์ฌ ๋ณด์ฌ์ง๊ณ ์๋ Destination ์ ๋ณด์ ๋ํ Getter
val currentRoute = navController.currentDestination?.route
items.forEach { item ->
NavigationBarItem(
selected = (item.route == currentRoute),
onClick = {
navController.navigate(item.route) {
// (3) popUpTo ๋์() ์ต์
(์ค๋ช
์ฐธ์กฐ)
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
// ๋ฐฑ์คํ์ ๋์ผํ Destination์ด ํน์ ์๋ค๋ฉด ๊ทธ๊ฑธ ์ฌ์ฌ์ฉํ๊ฒ ๋ง๋๋ ์ต์
launchSingleTop = true
// ์ด์ ์ ํด๋น Destination์ ์ ์ฅํ๋ ์ํ(์
๋ ฅํ๋ ๋ฌธ์์ด, ์คํฌ๋กค ์์น ๋ฑ)๊ฐ ์๋ค๋ฉด ๋ถ๋ฌ์ค๊ฒ ๋ง๋๋ ์ต์
restoreState = true
}
},
icon = {
Icon(
painterResource(id = item.iconId),
contentDescription = item.title
)
}
// (4) label์ ๋์์ธ์ ์ด์ ๋ก ์ ๊ฑฐํจ (์ค๋ช
์ฐธ์กฐ)
// label = { Text(text = item.title) }
)
}
}
(1) NavigationBar์ ๋ค์ด๊ฐ ์์ดํ ๋ฆฌ์คํธ
Destination ํด๋์ค์ ์์ ํด๋์ค๋ค์ ๋ฃ์๋ค.
(2) ํ์ฌ ๋ณด์ฌ์ง๊ณ ์๋ Destination ์ ๋ณด์ ๋ํ Getter
ํ์ฌ Navigation์ด ์ด๋ค Destination ์ ๋ณด๋ฅผ ๋ด๊ณ ์๋ ์ง ์๋ ค์ฃผ๋ ๋ณ์๋ค. ์ด ๋ณ์๋ NavigationBarItem์ selected ํ๋กํผํฐ์ ๊ฐ์ ๊ฒฐ์ ํ ๋ ์ฌ์ฉ๋๋ค. selected๊ฐ true์ผ๋, NavigationBaItem์ ์์ด์ฝ์ ๋ ๊ตต๊ฒ ํ์ํ๋ ์์ผ๋ก ํ์ฉ๊ฐ๋ฅํ ํ๋กํผํฐ๋ค.
(3) popUpTo() ๋์ ์ต์

NavigationBar์ ์์ดํ ์ด 1, 2, 3์ผ๋ก ์ด 3๊ฐ ์๊ณ , startDestination์ 1์ด๋ผ๊ณ ๊ฐ์ ํ๋ค. ํ์ฌ ์ ํ๋ ์์ดํ ์ 3์ด๊ณ , 3์์ ์ด๋ฐ ์ ๋ฐ ๊ณผ์ ์ ํตํด, 3', 3'', 3'''์ Destination์ ์์นํ ์ํ๋ค. ์ด ์ํ์์ NavigationBar์ ์์ดํ 2๋ฅผ ํด๋ฆญํด์ ํด๋น Destination์ ๋ฐฉ๋ฌธํ๋ ค๊ณ ํ๋ค.

์ด๋ popUpTo() ์ต์
์ด ์ ์ฉ๋ NavController.navigate()๊ฐ ์ํ๋๋ฉด 2๊น์ง ๋์๊ฐ๊ธฐ ์ํด ๋๋์๊ฐ ๊ฒฝ๋ก์ ๋ชจ๋ Destination์ ๋ฐฑ์คํ(์ด ๊ฒ์๊ธ์ #2-2 ์ฐธ์กฐ)์์ ์ญ์ ํ๋ค. ์ด ๋, popUpTo()์ ์ธ์๋ก ๋ค์ด๊ฐ๋ Destination์ id๊ฐ์ ๋ฐฑ์คํ์ ์ด๋ ๋ฏธ๋ง๊น์ง ์ญ์ ํ๋ ์ง์ ๊ธฐ์ค์ด ๋๋ค. ์ ์ฝ๋์ฒ๋ผ navController.graph.findStartDestination().id๋ฅผ ๊ธฐ์ค ์ผ์ผ๋ฉด startDestination๊น์ง์ ๋ชจ๋ Destination์ด ์ ๊ฑฐ๋๋๋ฐ, startDestination == ์ต์์ Destination์ด๋ฏ๋ก ์ต์์ Destination์ ์ ์ธํ๊ณ ์ ๋ถ ์ ๊ฑฐํ๊ฒ ๋ค๋ ์๋ฏธ๊ฐ ๋๋ค.
(4) label์ ๋์์ธ์ ์ด์ ๋ก ์ ๊ฑฐํจ
#4-1์ ์ด label ์์ฑ์ ์ ์ํด์ค ๋ฒ์ ๊ณผ ์๋ตํ ๋ฒ์ ๋ ๋ค ํ์ธํ ์ ์๋ค. ๋๋ ์์ด์ฝ๋ง์ผ๋ก Destination์ ๋ํด ์ถฉ๋ถํ ์ง๊ด์ ์ค๋ช ์ด ๊ฐ๋ฅํ๋ค๊ณ ์๊ฐํ๋ค. ๋ฐ๋ผ์ ์๋ตํ๋ค. ๋์ค์ ์ฌ์ฉ์ ํผ๋๋ฐฑ์ ๋ฐ์, label์ด ์๋ ํธ์ด ์ฌ์ฉ์ ๊ฒฝํ์์ ๊ณต๋ฆฌ์ ์ธ ์ด๋์ด ์๋ค๊ณ ์๊ฐ๋๋ค๋ฉด ๋ค์ ์ถ๊ฐํ๊ฒ ๋ค.
#3 ์์ฝ
NavigationBar๋ฅผ ๋ง๋ค์๋ค.
#4 ์์ฑ๋ ์ฑ
#4-1 ์คํฌ๋ฆฐ์ท

#4-2 ์ด ๊ฒ์๊ธ ์์ ์ Commit
GitHub - Kanmanemone/nutri-capture-new
Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.
github.com
#4-3 ๋ณธ ํ๋ก์ ํธ์ ๊ฐ์ฅ ์ต์ Commit
GitHub - Kanmanemone/nutri-capture-new
Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.
github.com
'๊ฐ๋ฐ ์ผ์ง ๐ป > Nutri Capture' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Nutri Capture ํ๋ก ํธ์๋ - NutrientScreen ๊ตฌ์กฐ ์ก๊ธฐ (1) | 2024.10.04 |
---|---|
Nutri Capture ๋ฐฉํฅ์ฑ - ๊ณ ์ ์ธ์ง๊ฐ๊ฐ, ์ UI ์ค์ผ์น (4) | 2024.10.03 |
Nutri Capture ํ๋ก ํธ์๋ - NavHost (1) | 2024.09.26 |
Nutri Capture ํ๋ก ํธ์๋ - Scaffold (0) | 2024.09.25 |
Nutri Capture ๋ฐฉํฅ์ฑ - ์ด์๋จ๋ ์ฑ์ด ๋๋ ค๋ฉด (0) | 2024.09.22 |