Scaffold
직역하면 "발판" 이라는 뜻인데 기존에도 사용되던 용어이지만 Android 에선 Compose 로 넘어오면서 생긴 요소입니다.
이름에 걸맞게 레이아웃에서 Top / Bottom Bar 부터 시작해서 SnackBar, FloatingButton, Drawer 와 같이
소위 미리 깔아두는 요소들을 세팅하고 , PaddingValues 를 후행 람다에서 수신하여
안에 들어갈 레이아웃과 겹치거나 하지 않도록 지원해주는 Composable 입니다.
그 중에서도 모바일에서 자주 사용되는 하단 네비게이션 바(Bottom Navigation Bar) 가 들어간 Screen 을 Scaffold 를 이용해서 그려봅시다.
BottomNavigation
fun BottomNavigation(
modifier: Modifier = Modifier,
backgroundColor: Color = MaterialTheme.colors.primarySurface,
contentColor: Color = contentColorFor(backgroundColor),
elevation: Dp = BottomNavigationDefaults.Elevation,
content: @Composable RowScope.() -> Unit
)
기본적으로 색상과 elevation 을 지정해 줄 수 있고 , 후행 람다에서 Row 를 채우는 형태입니다.
그리고 이 Row 안에 넣을 수 있는 BottomNavigationItem 을 지원해줍니다.
fun RowScope.BottomNavigationItem(
selected: Boolean,
onClick: () -> Unit,
icon: @Composable () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
label: @Composable (() -> Unit)? = null,
alwaysShowLabel: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
selectedContentColor: Color = LocalContentColor.current,
unselectedContentColor: Color = selectedContentColor.copy(alpha = ContentAlpha.medium)
)
Selected 는 이전에 공부했던 대로 State 로써 넣어줄 수 있을 것이고,
클릭 이벤트도 자체적으로 구현되어있어서 onClick 파라미터에 후행 람다로 이벤트를 넣어주면 됩니다.
일단 더 긴 설명보다도 간단한 예시로 한번 구현해보도록 하겠습니다.
data class BottomItem(
val route: String,
val labelStringId: Int,
val iconDrawableId: Int
)
object Destinations{
const val HOME_ROUTE = "home"
const val MENU_ROUTE_1 = "menu_1"
const val MENU_ROUTE_2 = "menu_2"
}
BottomNavigationItem 의 Parameter 를 채워줄 data class 와
Navigation 의 Destinations 를 임의로 만들어줍니다.
그리고 이 BottomItem 을 이용하여 하단 메뉴 리스트를 만들어주고
val items = listOf(
BottomItem(
route = Destinations.HOME_ROUTE,
labelStringId = R.string.label_home,
iconDrawableId = R.drawable.ic_home
),
BottomItem(
route = Destinations.MENU_ROUTE_1,
labelStringId = R.string.label_menu_1,
iconDrawableId = R.drawable.ic_menu_1
),
BottomItem(
route = Destinations.MENU_ROUTE_2,
labelStringId = R.string.label_menu_2,
iconDrawableId = R.drawable.ic_menu_2
)
)
이 메뉴리스트를 이용해서 아래와 같이 BottomBar 에 들어갈 BottomNavigation 을 구현해줍니다.
@Composable
fun BottomBar(navController: NavHostController, items: List<BottomItem>){
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
BottomNavigation(
backgroundColor = Color.Black,
contentColor = Color.White
) {
items.forEach {
BottomNavigationItem(
modifier = Modifier.size(56.dp),
selected = currentRoute == it.route,
onClick = {navController.navigate(it.route) },
icon = { Icon(painter = painterResource(id = it.iconDrawableId),
contentDescription = "") },
label = { Text(text = stringResource(id = it.labelStringId)) }
)
}
}
}
그리고 이 Composable 을 처음 설명했던 Scaffold 의 bottomBar 에 넣어주고,
후행 lambda(Content) 안에 NavHost 를 컴포저블로 감싼 뒤,
Modifier 의 padding 을 Scaffold 의 PaddingValue 로 설정해주면 됩니다.
@Composable
fun MainScreen(){
val navHostController = rememberNavController()
Scaffold(bottomBar = {
BottomBar(navController = navHostController, items = items)
}){
Box(modifier = Modifier.padding(it)){
NavHost(navController = navHostController,
startDestination = Destinations.HOME_ROUTE){
composable(Destinations.HOME_ROUTE){
ResultScreen(result = "홈 화면")
}
composable(Destinations.MENU_ROUTE_1){
ResultScreen(result = "첫 번째 메뉴 화면")
}
composable(Destinations.MENU_ROUTE_2){
ResultScreen(result = "두 번째 메뉴 화면")
}
}
}
}
}
여기에 사용된 ResultScreen 은 임의로 구현하시면 되지만 , 일단 아래와 같이 간단히 구현했습니다
@Composable
fun ResultScreen(result: String){
Box(modifier = Modifier.fillMaxSize()){
Text(
modifier = Modifier.align(Alignment.Center),
text = result,
fontSize = 30.sp,
fontWeight = FontWeight.SemiBold)
}
}
아무튼 위에서 구현된 MainScreen 을 Composable 의 Content에서 사용해주시면 됩니다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposableTheme {
MainScreen()
}
}
}
아래는 실행 영상 입니다.
'Android > Kotlin' 카테고리의 다른 글
LiveData 의 postValue() vs setValue() 의 차이점, 언제 사용해야 할까? (0) | 2024.03.29 |
---|---|
Android SpeechRecognizer 를 이용해 음성 인식 구현하기 (1) | 2024.02.29 |
Jetpack Compose 에서 Dialog 구현하기 (1) | 2024.02.07 |
Jetpack Compose 에서 ProgressBar 구현하기 (0) | 2024.02.05 |
Android Jetpack Hilt 를 이용하여 의존성 주입하기 (0) | 2024.01.22 |