Sam Story

2024-09-04 컴포즈 캘린더뷰 구현해보기 본문

공부기록

2024-09-04 컴포즈 캘린더뷰 구현해보기

Sam H 2024. 9. 4. 19:38

 

컴포즈로 커스텀 캘린더 뷰를 만들어 보기 위해서

먼저 컴포즈로 간단한 캘린더 뷰를 만들었다.

 

가장 기본적인 코드들을 이용해서 만들었는데

 

컴포즈는 일단 리사이클러뷰가 없다.

LazyColumn , LazyLow , LazyGrids 를 이용해서 View를 만들어야 하는데

 

만들다보니 느끼는 점은

TableLayout과 비슷한 속성을 다루는것 같았다.

 

만들어본 캘린더뷰 코드를 보자.

 

package com.example.composecustomcalendar

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
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 com.example.composecustomcalendar.ui.theme.ComposeCustomCalendarTheme
import java.time.YearMonth
import java.time.format.DateTimeFormatter
import java.util.Locale

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeCustomCalendarTheme {

                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {

                    MainContent()

                }
            }

        }
    }
}

@Composable
fun SetCalendarGrid(currentMonth: YearMonth) {

    // 일주일에 대한 리스트를 만든다.
    val daysOfWeek = listOf("일", "월", "화", "수", "목", "금", "토")

    // 해당 월의 첫번째 날을 나타내는 LocalDate 객체
    val firstDayOfMonth = currentMonth.atDay(1)

    // 주어진 달의 첫번째 날이 주의 몇번째 날인지 계산 계산하는 코드
    val dayOfWeekOffset = firstDayOfMonth.dayOfWeek.value % 7

    // 주어진 월에 몇일이 있는지를 계산해서 daysInMonth에 저장.
    val daysInMonth = currentMonth.lengthOfMonth()

    LazyVerticalGrid(
        columns = GridCells.Fixed(7),
        modifier = Modifier.fillMaxWidth()
    ) {

        // 요일 헤더 추가 리스트의 사이즈 만큼 순회하고 채운다.
        items(daysOfWeek.size) { index ->

            Text(
                text = daysOfWeek[index],
                textAlign = TextAlign.Center,
                modifier = Modifier.fillMaxWidth()
            )

        }

        // 빈 칸 추가
        // 첫번째 날이 주의 몇번째 날인지를 계산 후 그전까지 빈칸 처리
        items(dayOfWeekOffset) {
            Text(
                text = "",
                modifier = Modifier.fillMaxWidth()
            )
        }

        // 날짜를 추가
        // 한달이 며칠까지 있는지 계산 후 0부터 시작이니 1씩 더해서 날짜를 만들어준다.
        items(daysInMonth) { dayIndex ->
            val day = dayIndex + 1
            Text(
                text = "$day",
                textAlign = TextAlign.Center,
                modifier = Modifier.fillMaxWidth()
            )
        }

    }
}

@Composable
fun MainContent() {

    // 현재 날짜를 Mutable 값으로 초기화 한다.
    val currentMonth = remember { mutableStateOf(YearMonth.now()) }

    Column(
        modifier = Modifier.fillMaxSize(),

        // 컴포넌트들이 위에서부터 순차적으로 배치
        verticalArrangement = Arrangement.Top

    ) {

        CalendarTitle(

            currentMonth = currentMonth.value,

            onPreviousMonth = {

                currentMonth.value = currentMonth.value.minusMonths(1)

            },

            onNextMonth = {

                currentMonth.value = currentMonth.value.plusMonths(1)

            }

        )

        SetCalendarGrid(currentMonth = currentMonth.value)

    }

}

@Composable
fun CalendarTitle(

    currentMonth: YearMonth,

    // 메서드를 매개변수로 받는 듯?
    onPreviousMonth: () -> Unit,

    onNextMonth: () -> Unit

) {

    // 날짜 format 초기화
    val monthFormatter = DateTimeFormatter.ofPattern("yyyy년 MMMM", Locale.getDefault())

    Row(modifier = Modifier.fillMaxWidth(),
        horizontalArrangement = Arrangement.Center,
        verticalAlignment = Alignment.CenterVertically) {

        // 버튼 클릭시 onPreviousMonth 실행
        Button(onClick = onPreviousMonth,
        modifier = Modifier.padding(20.dp)) {

            Text("이전 날짜")

        }

        Text(text = currentMonth.format(monthFormatter))

        // 버튼 클릭시 onNextMonth 실행
        Button(onClick = onNextMonth,
            modifier = Modifier.padding(20.dp)) {

            Text("다음 날짜")

        }

    }

}


@Preview(showBackground = true)
@Composable
fun PreviewSetListColumn() {
    ComposeCustomCalendarTheme {

        MainContent()

    }
}

 

날짜 관련 속성들은 GPT를 참고해서 코드를 짰고

나머지 레이아웃을 컴포즈를 이용해서 짜보았는데 돌아가는 구조 자체가 복잡하진 않은

간단한 캘린더뷰다.

 

실행 결과

실행 결과

이전 날짜 버튼과 다음날짜 버튼을 누르면 날짜가 바뀌는

기본적인 캘린더 뷰를 만들어 보았다.

 

이 코드에서 좀 더 발전시켜 괜찮은 커스텀 캘린더 뷰를 만든 후

다시 포스팅 해야겠다..