kotlinx-datetime라이브러리 필요
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlinx.datetime.Clock
import kotlinx.datetime.DateTimeUnit
import kotlinx.datetime.LocalDate
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.plus
import kotlinx.datetime.toLocalDateTime
@Composable
fun CalendarView(
start: LocalDateTime = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())
) {
var year by remember {
mutableIntStateOf(start.year)
}
var month by remember {
mutableIntStateOf(start.monthNumber)
}
Column {
// 현재 날짜 정보
Row(
Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text("${year}년 ${month}월", Modifier.padding(8.dp))
Row {
Button(
onClick = {
if (month == 1) {
year -= 1
month = 12
} else {
month -= 1
}
}
) {
Text("<")
}
Button(
onClick = {
if (month == 12) {
year += 1
month = 1
} else {
month += 1
}
}
) {
Text(">")
}
}
}
// 요일 헤더 추가
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceAround) {
listOf("일", "월", "화", "수", "목", "금", "토").forEach { day ->
Text(
day,
Modifier.weight(1f),
textAlign = androidx.compose.ui.text.style.TextAlign.Center
)
}
}
Spacer(modifier = Modifier.height(8.dp))
val daysInMonth = getDaysOfMonthWithOffset(year, month)
// 달력 표시 (7열 고정)
LazyVerticalGrid(
columns = GridCells.Fixed(7),
modifier = Modifier.height(25.dp * 6)
) {
items(daysInMonth) { day ->
Text(
text = day?.dayOfMonth?.toString() ?: "",
textAlign = TextAlign.Center,
modifier = Modifier.height(25.dp)
)
}
}
}
}
// 해당 연도와 월의 모든 날짜 리스트 반환 (빈 칸 포함)
fun getDaysOfMonthWithOffset(year: Int, month: Int): List<LocalDate?> {
val firstDay = LocalDate(year, month, 1)
val firstDayOfWeek = firstDay.dayOfWeek.ordinal // 0(월) ~ 6(일) → 한국 기준 일요일이 6
val days = mutableListOf<LocalDate?>()
// 빈 칸 추가 (일요일부터 시작해야 하므로 shift 조정)
repeat((firstDayOfWeek + 1) % 7) { days.add(null) }
// 날짜 추가
var currentDay = firstDay
val nextMonth = if (month == 12) 1 else month + 1
val nextYear = if (month == 12) year + 1 else year
val firstDayOfNextMonth = LocalDate(nextYear, nextMonth, 1)
while (currentDay < firstDayOfNextMonth) {
days.add(currentDay)
currentDay = currentDay.plus(1, DateTimeUnit.DAY)
}
return days
}
@Preview(showBackground = true)
@Composable
fun CalendarViewPreview() {
CalendarView()
}