안녕하세요 이번 포스팅은 위 사진처럼 바텀 네비게이션 레이아웃을 이용하여 간단한 화면전환을 해보도록 하겠습니다.
앱 수준의 build.gradle
로 들어가서 다음과 같은 종속항목을 추가해줍니다.
implementation "androidx.navigation:navigation-compose:2.4.1"
MainActivity 하단에 컴포저블 함수를 지정하여 각각의 화면을 구성해줍니다.
@Composable
fun HomeScreen() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(text = "Home screen")
}
}
@Composable
fun ChatScreen() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(text = "Chat screen")
}
}
@Composable
fun SettingsScreen() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(text = "Settings screen")
}
}
처음에 시작할 화면과, 각각의 화면에 대한 루트를 지정합니다.
@Composable
fun Navigation(navController: NavHostController) {
NavHost(navController = navController, startDestination = "home") {
composable("home") {
HomeScreen()
}
composable("chat") {
ChatScreen()
}
composable("settings") {
SettingsScreen()
}
}
}
하단 콘텐츠에는 아이콘 명, 루트 이름, 아이콘 이미지, 뱃지카운트를 넣을 것이기 때문에 data class 의 파라미터로 정의해줍니다.
import androidx.compose.ui.graphics.vector.ImageVector
data class BottomNavItem (
val name: String,
val route: String,
val icon: ImageVector,
val badgeCount: Int = 0
)
하단 네비게이션 레이아웃을 구성하고 아이템 상태 변화에 대한 스타일 처리를 해줍니다.
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun BottomNavigationBar(
items: List<BottomNavItem>,
navController: NavHostController,
modifier: Modifier = Modifier,
onItemClick: (BottomNavItem) -> Unit
) {
val backStackEntry = navController.currentBackStackEntryAsState()
BottomNavigation (
modifier = modifier,
backgroundColor = Color.DarkGray,
elevation = 5.dp
) {
// items 배열에 담긴 모든 항목을 추가합니다.
items.forEach { item ->
// 뷰의 활동 상태를 백스택에 담아 저장합니다.
val selected = item.route == backStackEntry.value?.destination?.route
BottomNavigationItem(
selected = selected,
onClick = { onItemClick(item) },
selectedContentColor = Color.Green,
unselectedContentColor = Color.Gray,
icon = {
Column(horizontalAlignment = CenterHorizontally) {
// 뱃지카운트가 1이상이면, 아이콘에 뱃지카운트가 표시됩니다.
if (item.badgeCount > 0) {
BadgeBox(
badgeContent = {
Text(text = item.badgeCount.toString())
}
) {
Icon(
imageVector = item.icon,
contentDescription = item.name
)
} // 뱃지 카운트가 0이면, 아이콘만 표시합니다.
} else {
Icon(
imageVector = item.icon,
contentDescription = item.name
)
}
// 아이콘이 선택 되었을 때, 아이콘 밑에 텍스트를 표시합니다.
if (selected) {
Text(
text = item.name,
textAlign = TextAlign.Center,
fontSize = 10.sp
)
}
}
}
)
}
}
}
이제 기본적인 세팅은 끝났고, 메인 화면에 지금까지 정의한 뷰를 띄울겁니다. 아이템 리스트를 정의하고 네이게이션 컨트롤러와 연결시켜주시면 됩니다.
scaffold
는 안드로이드에 스낵바, 바텀 네비게이션바 등의 UI를 추가하기 위한 라이브러리입니다.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
Scaffold(
bottomBar = {
BottomNavigationBar(
items = listOf(
BottomNavItem(
name = "Home",
route = "home",
icon = Icons.Default.Home
),
BottomNavItem(
name = "Chat",
route = "chat",
icon = Icons.Default.Notifications,
badgeCount = 24
),
BottomNavItem(
name = "Settings",
route = "settings",
icon = Icons.Default.Settings
)
),
navController = navController,
onItemClick = {
navController.navigate(it.route)
})
}
) {
Navigation(navController = navController)
}
}
}
}
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
Scaffold(
bottomBar = {
BottomNavigationBar(
items = listOf(
BottomNavItem(
name = "Home",
route = "home",
icon = Icons.Default.Home
),
BottomNavItem(
name = "Chat",
route = "chat",
icon = Icons.Default.Notifications,
badgeCount = 24
),
BottomNavItem(
name = "Settings",
route = "settings",
icon = Icons.Default.Settings
)
),
navController = navController,
onItemClick = {
navController.navigate(it.route)
})
}
) {
Navigation(navController = navController)
}
}
}
}
@Composable
fun Navigation(navController: NavHostController) {
NavHost(navController = navController, startDestination = "home") {
composable("home") {
HomeScreen()
}
composable("chat") {
ChatScreen()
}
composable("settings") {
SettingsScreen()
}
}
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun BottomNavigationBar(
items: List<BottomNavItem>,
navController: NavHostController,
modifier: Modifier = Modifier,
onItemClick: (BottomNavItem) -> Unit
) {
val backStackEntry = navController.currentBackStackEntryAsState()
BottomNavigation(
modifier = modifier,
backgroundColor = Color.DarkGray,
elevation = 5.dp
) {
// items 배열에 담긴 모든 항목을 추가합니다.
items.forEach { item ->
// 뷰의 활동 상태를 백스택에 담아 저장합니다.
val selected = item.route == backStackEntry.value?.destination?.route
BottomNavigationItem(
selected = selected,
onClick = { onItemClick(item) },
selectedContentColor = Color.Green,
unselectedContentColor = Color.Gray,
icon = {
Column(horizontalAlignment = CenterHorizontally) {
// 뱃지카운트가 1이상이면, 아이콘에 뱃지카운트가 표시됩니다.
if (item.badgeCount > 0) {
BadgeBox(
badgeContent = {
Text(text = item.badgeCount.toString())
}
) {
Icon(
imageVector = item.icon,
contentDescription = item.name
)
} // 뱃지 카운트가 0이면, 아이콘만 표시합니다.
} else {
Icon(
imageVector = item.icon,
contentDescription = item.name
)
}
// 아이콘이 선택 되었을 때, 아이콘 밑에 텍스트를 표시합니다.
if (selected) {
Text(
text = item.name,
textAlign = TextAlign.Center,
fontSize = 10.sp
)
}
}
}
)
}
}
}
@Composable
fun HomeScreen() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(text = "Home screen")
}
}
@Composable
fun ChatScreen() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(text = "Chat screen")
}
}
@Composable
fun SettingsScreen() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(text = "Settings screen")
}
}
왜 home과 setting에는 badgecount를 파라미터로 넣지 않았나요??